Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ applications — the HTTP response.

## Upgrading

* [Updating from v1 to v2](v1-to-v2-update.md)
* [Updating from v2 to v3](v2-to-v3-update.md)
* [Updating from v3 to v4](v3-to-v4-update.md)
* [Updating from v1 to v2](v1-to-v2-update.md) — CLI and daemon classes removed, PSR-7 responses,
application events, interfaces
* [Updating from v2 to v3](v2-to-v3-update.md) — PHP 8.1, PSR-12, no API changes
* [Updating from v3 to v4](v3-to-v4-update.md) — PHP 8.3, the `$app->input` getter and the boolean
redirect status removed
244 changes: 220 additions & 24 deletions docs/v1-to-v2-update.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,238 @@
## Updating from v1 to v2
# Updating from v1 to v2

The following changes were made to the Application package between v1 and v2.
Release 2.0.0 is the largest change in the package's history. It removes the CLI and daemon
application classes, introduces PSR-7 responses, adds the event lifecycle, and splits the
application contract into interfaces.

### Minimum supported PHP version raised
## At a glance

All Framework packages now require PHP 7.2 or newer.
| | v1 (1.9.3) | v2 (2.0.0) |
|---|---|---|
| PHP | `^5.3.10 \| ^7.0 \| ^8.0` | `^7.2.5` |
| Application types | Web, CLI, Daemon | Web only |
| Response | Internal `stdClass` | PSR-7 `ResponseInterface` |
| Events | Comment placeholders only | Dispatched via `joomla/event` |
| Interfaces | none | four, see below |
| `joomla/input` | required | suggested |

### PSR-7 Responses now supported
In order to support PSR-7 responses there is a single break in backwards incompatibility. The `\Joomla\Application\AbstractWebApplication::getBody()` method does not have a `toBody` parameter.
## Minimum supported PHP version raised

The package internals use the Laminas [Diactoros package](https://github.com/laminas/laminas-diactoros) for building the Response object. If you wish to use another PSR-7 compatible library you will need to extend the `setHeader`, `getHeaders`, `clearHeaders`, `setBody`, `prependBody`, and `appendBody` methods.
All Framework packages now require **PHP 7.2.5** or newer.

### AbstractWebApplication::checkToken now validates a token
The method `\Joomla\Application\AbstractWebApplication::checkToken` has been changed to validate a token in addition to checking if it is present in the request. Additionally, the homepage redirect on an invalid token has been removed.
## CLI and daemon classes removed

### CLI Classes Removed
The following were removed with no replacement in this package:

The `\Joomla\Application\AbstractCliApplication` and all `Joomla\Application\Cli` namespace classes have been removed. The new `joomla/console` package should be used going forward.
* `Joomla\Application\AbstractCliApplication`
* `Joomla\Application\AbstractDaemonApplication`
* the entire `Joomla\Application\Cli` namespace — `CliInput`, `CliOutput`, `ColorProcessor`,
`ColorStyle`, `Output\Stdout`, `Output\Xml`, `Output\Processor\ColorProcessor`,
`Output\Processor\ProcessorInterface`

### Added a concrete web application
Use the [`joomla/console`](https://github.com/joomla-framework/console) package for command line
applications. It builds on `AbstractApplication`, so configuration, logging and events work the
same way.

There is a new `\Joomla\Application\WebApplication` class available which serves as a minimal but functional web application class. This class extends `\Joomla\Application\AbstractWebApplication` and implements `\Joomla\Application\SessionAwareWebApplicationInterface` and therefore makes all application features available out-of-the-box.
There is no replacement for `AbstractDaemonApplication`. Its `pcntl` based process handling
(`daemonize()`, `fork()`, `detach()`, `restart()`, `stop()`, `writeProcessIdFile()`,
`loadConfiguration()` and the signal handlers) is gone entirely. Run long living processes under a
supervisor such as systemd or Supervisor instead.

### `$input` property moved to web application classes
## `AbstractApplication::__construct()` signature changed

The `$input` property of `\Joomla\Application\AbstractApplication` has been moved to `\Joomla\Application\AbstractWebApplication` and is no longer required to create a minimal application. With the introduction of the `joomla/console` package, which does not use the `joomla/input` package to read the console input, it is no longer practical to require all application classes support this input API.
The input object is no longer a concern of the base application class, so it was dropped from the
constructor:

Additionally, direct access to the property has been deprecated. To access the input, you should use the `\Joomla\Application\AbstractWebApplication::getInput()` method. Direct read access to the property will be removed in 3.0.
```php
// v1
public function __construct(Input $input = null, Registry $config = null)

### Session functionality moved to new application interface/trait
// v2
public function __construct(Registry $config = null)
```

As sessions are not a mandatory function of web applications, session related functionality has been moved to a new `\Joomla\Application\SessionAwareWebApplicationInterface` extending `\Joomla\Application\WebApplicationInterface`. `\Joomla\Application\SessionAwareWebApplicationTrait` is provided to simplify implementing this interface in your application.
If you extend `AbstractApplication` directly and call `parent::__construct($input, $config)`, the
config object is now silently passed as the input. Update the call.

### Interfaces for application classes
`AbstractWebApplication::__construct()` keeps its input argument and gains a fourth one for the
response:

Interfaces have been created for the application classes with the following structure:
```php
// v1
public function __construct(Input $input = null, Registry $config = null, WebClient $client = null)

- `\Joomla\Application\ApplicationInterface` defines the base requirements for all applications
- `\Joomla\Application\ConfigurationAwareApplicationInterface` defines an application which is aware of a configuration object
- `\Joomla\Application\WebApplicationInterface` defines a web application handling HTTP requests and serving HTTP responses
- `\Joomla\Application\SessionAwareWebApplicationInterface` defines a web application which requires session support
// v2
public function __construct(
Input $input = null,
Registry $config = null,
WebClient $client = null,
ResponseInterface $response = null
)
```

## `$input` property moved to the web application classes

The `$input` property moved from `AbstractApplication` to `AbstractWebApplication`. With
`joomla/console` handling console input differently, requiring every application to carry a
`joomla/input` object was no longer practical. `joomla/input` therefore moved from `require` to
`suggest` in `composer.json`.

Direct access to the property was deprecated in favour of the new `getInput()` method:

```php
// Deprecated in 2.0, still works via a magic getter
$app->input->getInt('id');

// Correct
$app->getInput()->getInt('id');
```

> The magic getter was announced for removal in 3.0 but actually survived the whole 3.x series. It
> was removed in **4.0.0** — see [Updating from v3 to v4](v3-to-v4-update.md).

## PSR-7 responses

The response is now a PSR-7 `ResponseInterface` instead of an internal `stdClass`. Two new methods
expose it:

```php
$response = $app->getResponse();
$app->setResponse($response->withStatus(201));
```

This causes one backwards incompatible change in the public API: **`getBody()` lost its
parameter.**

```php
// v1 — could return the internal array of body parts
public function getBody($asArray = false)

// v2 — always returns a string
public function getBody()
```

Replace `getBody(true)` with `getBody()` and split the string yourself if you relied on the array
form.

The package uses [Laminas Diactoros](https://github.com/laminas/laminas-diactoros) to build the
response. To use a different PSR-7 implementation, override `setHeader()`, `getHeaders()`,
`clearHeaders()`, `setBody()`, `prependBody()` and `appendBody()`.

## Application events

v1 marked the lifecycle with `// @event onBeforeExecute` comments and dispatched nothing. v2
dispatches real events through `joomla/event`, which became a required dependency.

```php
use Joomla\Application\ApplicationEvents;
use Joomla\Event\Dispatcher;

$app->setDispatcher(new Dispatcher());
```

New classes:

* `Joomla\Application\ApplicationEvents` — the event name constants `BEFORE_EXECUTE`,
`AFTER_EXECUTE`, `ERROR`, `BEFORE_RESPOND`, `AFTER_RESPOND`
* `Joomla\Application\Event\ApplicationEvent` — carries the application
* `Joomla\Application\Event\ApplicationErrorEvent` — carries the application and the `Throwable`

`AbstractApplication::execute()` now catches every `Throwable` from `doExecute()` and dispatches
`ApplicationEvents::ERROR` instead of letting it bubble up. **If you do not register a listener for
that event, an exception produces an empty response with status 200.** See
[Lifecycle and events](lifecycle-and-events.md#error-handling).

Attaching a dispatcher is optional: `dispatchEvent()` returns `null` when none is set.

## Controller resolvers

New in v2, for turning a route into a callable:

* `Joomla\Application\Controller\ControllerResolverInterface`
* `Joomla\Application\Controller\ControllerResolver`
* `Joomla\Application\Controller\ContainerControllerResolver` — resolves from a PSR-11 container

See [Routing and controllers](routing-and-controllers.md).

## A concrete web application

`Joomla\Application\WebApplication` is a minimal but functional web application. It extends
`AbstractWebApplication`, implements `SessionAwareWebApplicationInterface`, and dispatches a
request to a controller using a router and a controller resolver:

```php
$app = new WebApplication(
new ContainerControllerResolver($container),
$router,
$input,
$config
);

$app->execute();
```

## Session functionality moved to an interface and trait

Sessions are not mandatory for a web application, so the session methods moved out of
`AbstractWebApplication` into:

* `Joomla\Application\SessionAwareWebApplicationInterface` — extends `WebApplicationInterface`
* `Joomla\Application\SessionAwareWebApplicationTrait` — the implementation

The type hint also changed from the concrete class to the interface:

```php
// v1
public function setSession(Session $session)

// v2
public function setSession(SessionInterface $session)
```

## `checkToken()` now validates the token

`checkToken()` previously only checked whether the token was *present* in the request. It now
validates it. The redirect to `index.php` on a new session was removed — the method returns a
boolean and leaves the reaction to you:

```php
// v1 behaviour: could redirect and close the application
$app->checkToken();

// v2 behaviour: returns false, you decide
if (!$app->checkToken()) {
$app->setHeader('Status', '403', true);
$app->setBody('Invalid CSRF token.');

return;
}
```

## Interfaces for application classes

The application contract is now expressed as four interfaces:

| Interface | Defines |
|---|---|
| `ApplicationInterface` | The base requirements for all applications |
| `ConfigurationAwareApplicationInterface` | An application aware of a configuration object |
| `WebApplicationInterface` | A web application handling HTTP requests and serving HTTP responses |
| `SessionAwareWebApplicationInterface` | A web application which requires session support |

Type your own services against these rather than against the abstract classes.

## Dependency changes

| Package | v1 (1.9.3) | v2 (2.0.0) |
|---|---|---|
| `php` | `^5.3.10 \| ^7.0 \| ^8.0` | `^7.2.5` |
| `joomla/input` | `^1.2` (required) | moved to `suggest` |
| `joomla/registry` | `^1.4.5 \| ^2.0` | `^1.4.5 \| ^2.0` |
| `psr/log` | `^1.0` | `^1.0` |
| `joomla/event` | — | `^2.0` (new) |
| `laminas/laminas-diactoros` | — | `^2.2.2` (new) |
| `psr/http-message` | — | `^1.0` (new) |
| `symfony/deprecation-contracts` | — | `^2.1` (new) |

New optional dependencies (`suggest`): `joomla/controller`, `joomla/input`, `joomla/router`,
`joomla/session`, `joomla/uri`, `psr/container`.
89 changes: 85 additions & 4 deletions docs/v2-to-v3-update.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,88 @@
## Updating from v2 to v3
# Updating from v2 to v3

The following changes were made to the Application package between v1 and v2.
Release 3.0.0 is a small upgrade. It raises the PHP requirement, moves the codebase to PSR-12, and
removes one response header. **No public or protected method signature changed**, so code written
against 2.x keeps working as long as it runs on PHP 8.1.

### Minimum supported PHP version raised
## At a glance

All Framework packages now require PHP 8.1 or newer.
| | v2 (2.0.4) | v3 (3.0.0) |
|---|---|---|
| PHP | `^7.2.5` | `^8.1.0` |
| Public API | — | unchanged |
| Coding style | Joomla Coding Standard | PSR-12 |
| `X-Content-Encoded-By` header | sent when compressing | removed |

## Minimum supported PHP version raised

All Framework packages now require **PHP 8.1** or newer.

## The `X-Content-Encoded-By` header is no longer sent

`AbstractWebApplication::compress()` used to add a third header alongside the encoding headers:

```php
$this->setHeader('Content-Encoding', $encoding);
$this->setHeader('Vary', 'Accept-Encoding');
$this->setHeader('X-Content-Encoded-By', 'Joomla'); // removed in 3.0.0
```

The header carried no functional meaning and had been considered obsolete since 2013. It is simply
gone — compressed responses now carry `Content-Encoding` and `Vary` only.

This matters if you assert on response headers in tests, or if a downstream system reads
`X-Content-Encoded-By` to identify the application. Set it yourself if you still need it:

```php
$dispatcher->addListener(
ApplicationEvents::BEFORE_RESPOND,
static fn ($event) => $event->getApplication()->setHeader('X-Content-Encoded-By', 'Joomla')
);
```

## Codebase converted to PSR-12

The whole package was reformatted from the Joomla Coding Standard to PSR-12 (tabs to spaces, brace
placement, import ordering). This touches nearly every line but changes no behaviour.

Two practical consequences:

* A `git diff` between 2.x and 3.x is almost entirely noise. Use `git diff -w` or compare method
signatures when looking for real changes.
* If you maintain patches against this package, expect all of them to conflict. Reapply rather than
rebase.

The `joomla/coding-standards` dev dependency was replaced by `squizlabs/php_codesniffer` with a
PSR-12 ruleset.

## No API changes

Every `public` and `protected` method in `src/` has the same name and signature in 3.0.0 as in
2.0.4. The `Web\WebClient` constants are unchanged too. Upgrading is a matter of satisfying the PHP
and dependency requirements.

## Dependency changes

| Package | v2 (2.0.4) | v3 (3.0.0) |
|---|---|---|
| `php` | `^7.2.5` | `^8.1.0` |
| `joomla/event` | `^2.0` | `^3.0` |
| `joomla/registry` | `^1.4.5 \| ^2.0` | `^3.0` |
| `psr/log` | `^1.0` | `^1.0 \| ^2.0 \| ^3.0` |
| `psr/http-message` | `^1.0` | `^1.0` |
| `laminas/laminas-diactoros` | `^2.2.2` | `^2.24.0` |
| `symfony/deprecation-contracts` | `^2.1` | `^2 \| ^3` |

The optional packages in `suggest` moved to their 3.x releases: `joomla/controller`,
`joomla/input`, `joomla/router`, `joomla/session` and `joomla/uri` are all `^3.0`.
`psr/container` stays at `^1.0`.

## Deprecations still in place

The following were deprecated in 2.0 and **still work in 3.x**. Both were removed in 4.0.0 — see
[Updating from v3 to v4](v3-to-v4-update.md):

* Reading `$app->input` directly instead of calling `$app->getInput()`
* Passing a boolean as the `$status` argument of `redirect()`

Fixing them while still on 3.x makes the move to 4.0 a no-op.
Loading
Loading