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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Removed

- The ability to use `string`s to reference services

### Fixed

- PHP `8.4` deprecations
Expand Down
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"innmind/cli": "^3.1",
"innmind/immutable": "~5.2",
"innmind/di": "~2.1",
"ramsey/uuid": "^4.7",
"innmind/url": "^4.1",
"innmind/filesystem": "~7.0",
"innmind/http-server": "~4.0",
Expand Down
19 changes: 14 additions & 5 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ use Innmind\CLI\{
Console,
Command,
};
use Innmind\DI\Container;
use Innmind\DI\{
Container,
Service,
};
use Innmind\AMQP\{
Client,
Command\Publish,
Expand All @@ -45,13 +48,19 @@ use Innmind\AMQP\{
};
use Innmind\Immutable\Str;

enum Services implements Service
{
case producerClient;
case consumerClient;
}

new class extends Cli {
protected function configure(Application $app): Application
{
return $app
->service('producer-client', /* see services topic */)
->service('consumer-client', /* see services topic */)
->command(static fn(Container $container) => new class($container('producer-client')) implements Command {
->service(Services::producerClient, /* see services topic */)
->service(Services::consumerClient, /* see services topic */)
->command(static fn(Container $container) => new class($container(Services::producerClient)) implements Command {
public function __construct(
private Client $amqp,
) {
Expand Down Expand Up @@ -82,7 +91,7 @@ new class extends Cli {
return 'publish url';
}
})
->command(static fn(Container $container) => new class($container('consumer-client')) implements Command {
->command(static fn(Container $container) => new class($container(Services::consumerClient)) implements Command {
public function __construct(
private Client $amqp,
) {
Expand Down
30 changes: 20 additions & 10 deletions docs/http-and-cli.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Build an app that runs through HTTP and CLI

If you looked at how to build an [HTTP](http.md) and [CLI](cli.md) app you may have noticed that we always configure the same `Application` class. This is intentional to allow you to configure services once (in a [middleware](middlewares)) and use them in both contexts.
If you looked at how to build an [HTTP](http.md) and [CLI](cli.md) app you may have noticed that we always configure the same `Application` class. This is intentional to allow you to configure services once (in a [middleware](middlewares.md)) and use them in both contexts.

Let's take an imaginary app where you can upload images via HTTP (persists them to the filesystem) and a CLI command that pulls a message from an AMQP queue to build the thumbnail. We would build a middleware that roughly looks like this:

Expand All @@ -12,34 +12,44 @@ use Innmind\Framework\{
Http\Service,
};
use Innmind\OperatingSystem\OperatingSystem;
use Innmind\DI\Container;
use Innmind\DI\{
Container,
Service,
};
use Innmind\Router\Route;
use Innmind\Url\Path;

enum Services implements Service
{
case images;
case amqp;
case upload;
}

final class Kernel implements Middleware
{
public function __invoke(Application $app): Application
{
return $app
->service(
'images',
Services::images,
static fn($_, OperatingSystem $os) => $os
->filesystem()
->mount(Path::of('somewhere/on/the/filesystem/')),
)
->service('amqp', /* see services topic */)
->service('upload', static fn(Container $container) => new UploadHandler( //(1)
$container('images'),
$container('amqp'),
->service(Services::amqp, /* see services topic */)
->service(Services::upload, static fn(Container $container) => new UploadHandler( //(1)
$container(Services::images),
$container(Services::amqp),
))
->appendRoutes(
static fn(Routes $routes, Container $container) => $routes->add(
Route::literal('POST /upload')->handle(Service::of($container, 'upload')),
Route::literal('POST /upload')->handle(Service::of($container, Services::upload)),
),
)
->command(static fn(Container $container) => new ThumbnailWorker( //(2)
$container('images'),
$container('amqp'),
$container(Services::images),
$container(Services::amqp),
));
}
}
Expand Down
21 changes: 15 additions & 6 deletions docs/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ new class extends Http {
};
```

For simple apps having the whole behaviour next to the route can be ok. But like in this case it can be repetitive, for such case we can specify our behaviours elsewhere: [services](#Services).
For simple apps having the whole behaviour next to the route can be ok. But like in this case it can be repetitive, for such case we can specify our behaviours elsewhere: [services](#services).

## Multiple methods for the same path

Expand Down Expand Up @@ -203,7 +203,10 @@ use Innmind\Framework\{
Http\Service,
Http\To,
};
use Innmind\DI\Container;
use Innmind\DI\{
Container,
Service,
};
use Innmind\Router\{
Route,
Route\Variables,
Expand All @@ -215,12 +218,18 @@ use Innmind\Http\Message\{
};
use Innmind\Filesystem\File\Content;

enum Services implements Service
{
case helloWorld;
case helloName;
}

new class extends Http {
protected function configure(Application $app): Application
{
return $app
->service(
'hello-word',
Services::helloWorld,
static fn() => new class {
public function __invoke(ServerRequest $request): Response
{
Expand All @@ -234,7 +243,7 @@ new class extends Http {
}
)
->service(
'hello-name',
Services::helloName,
static fn() => new class {
public function __invoke(
ServerRequest $request,
Expand All @@ -252,11 +261,11 @@ new class extends Http {
->appendRoutes(
static fn(Routes $routes, Container $container) => $routes->add(
Route::literal('GET /')->handle(
Service::of($container, 'hello-word'),
Service::of($container, Services::helloWorld),
),
),
)
->route('GET /{name}', To::service('hello-name'));
->route('GET /{name}', To::service(Services::helloName));
}
};
```
Expand Down
25 changes: 19 additions & 6 deletions docs/middlewares.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Middlewares

Middlewares are a way to regroup all the configuration you've seen in other topics under a name. This means that you can either group part of your own application undeer a middleware or expose a package for other to use via Packagist.
Middlewares are a way to regroup all the configuration you've seen in other topics under a name. This means that you can either group part of your own application under a middleware or expose a package for other to use via Packagist.

!!! note ""
You can search for [`innmind/framework-middlewares` on Packagist](https://packagist.org/providers/innmind/framework-middlewares) for middlewares published by others.
Expand All @@ -12,33 +12,41 @@ use Innmind\Framework\{
Middleware,
Environment,
};
use Innmind\DI\Container;
use Innmind\DI\{
Container,
Service,
};
use Innmind\CLI\{
Console,
Command,
};
use Innmind\Url\Url;

enum Services implements Service
{
case emailServer;
}

final class Emails implements Middleware
{
public function __construct(
private string $service,
private Service $service,
){
}

public function __invoke(Application $app): Application
{
return $app
->service(
'email-server'
Services::emailServer
static fn($_, $__, Environment $env) => Url::of(
$env->get('EMAIL_SERVER'),
),
),
->service(
$this->service,
static fn(Container $container) => new EmailClient( //(1)
$container('email-server'),
$container(Services::emailServer),
),
)
->command(
Expand Down Expand Up @@ -75,10 +83,15 @@ use Innmind\Framework\{
Application,
};

enum MyServices implements Service
{
case emailClient;
}

new class extends Cli {
protected function configure(Application $app): Application
{
return $app->map(new Emails('email-client-service-name'));
return $app->map(new Emails(MyServices::emailClient));
}
};
```
Expand Down
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ final class AppTest extends TestCase
]))
->map(new Kernel)
->mapRequestHandler(
fn($handler, $container) => new class($handler, $container('pdo'), $this) implements RequestHandler {
fn($handler, $container) => new class($handler, $container(Services::pdo), $this) implements RequestHandler {
public function __construct(
private RequestHandler $handler,
private \PDO $pdo,
Expand Down
3 changes: 1 addition & 2 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,11 @@ public function map(Middleware $map): self
/**
* @psalm-mutation-free
*
* @param non-empty-string|Service $name
* @param callable(Container, OperatingSystem, Environment): object $definition
*
* @return self<I, O>
*/
public function service(string|Service $name, callable $definition): self
public function service(Service $name, callable $definition): self
{
return new self($this->app->service($name, $definition));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Application/Async/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ static function(OperatingSystem $os, Environment $env) use ($previous, $map): ar
* @psalm-mutation-free
*/
#[\Override]
public function service(string|Service $name, callable $definition): self
public function service(Service $name, callable $definition): self
{
$container = $this->container;

Expand Down
29 changes: 13 additions & 16 deletions src/Application/Cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
Sequence,
Str,
};
use Ramsey\Uuid\Uuid;

/**
* @internal
Expand All @@ -34,7 +33,7 @@ final class Cli implements Implementation
private Environment $env;
/** @var callable(OperatingSystem, Environment): Builder */
private $container;
/** @var Sequence<string> */
/** @var Sequence<callable(Container, OperatingSystem, Environment): Command> */
private Sequence $commands;
/** @var callable(Command, Container, OperatingSystem, Environment): Command */
private $mapCommand;
Expand All @@ -43,7 +42,7 @@ final class Cli implements Implementation
* @psalm-mutation-free
*
* @param callable(OperatingSystem, Environment): Builder $container
* @param Sequence<string> $commands
* @param Sequence<callable(Container, OperatingSystem, Environment): Command> $commands
* @param callable(Command, Container, OperatingSystem, Environment): Command $mapCommand
*/
private function __construct(
Expand All @@ -69,7 +68,7 @@ public static function of(OperatingSystem $os, Environment $env): self
$os,
$env,
static fn() => Builder::new(),
Sequence::strings(),
Sequence::of(),
static fn(Command $command) => $command,
);
}
Expand Down Expand Up @@ -110,7 +109,7 @@ public function mapOperatingSystem(callable $map): self
* @psalm-mutation-free
*/
#[\Override]
public function service(string|Service $name, callable $definition): self
public function service(Service $name, callable $definition): self
{
$container = $this->container;

Expand All @@ -132,16 +131,12 @@ public function service(string|Service $name, callable $definition): self
#[\Override]
public function command(callable $command): self
{
/** @psalm-suppress ImpureMethodCall Mutation free to force the user to use the returned object */
$reference = Uuid::uuid4()->toString();
$self = $this->service($reference, $command);

return new self(
$self->os,
$self->env,
$self->container,
($self->commands)($reference),
$self->mapCommand,
$this->os,
$this->env,
$this->container,
($this->commands)($command),
$this->mapCommand,
);
}

Expand Down Expand Up @@ -221,9 +216,11 @@ public function run($input)
$os,
$env,
);
$commands = $this->commands->map(static fn($service) => new Defer(
$service,
$commands = $this->commands->map(static fn($command) => new Defer(
$command,
$container,
$os,
$env,
$mapCommand,
));

Expand Down
2 changes: 1 addition & 1 deletion src/Application/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function mapOperatingSystem(callable $map): self
* @psalm-mutation-free
*/
#[\Override]
public function service(string|Service $name, callable $definition): self
public function service(Service $name, callable $definition): self
{
$container = $this->container;

Expand Down
3 changes: 1 addition & 2 deletions src/Application/Implementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ public function mapOperatingSystem(callable $map): self;
/**
* @psalm-mutation-free
*
* @param non-empty-string|Service $name
* @param callable(Container, OperatingSystem, Environment): object $definition
*
* @return self<I, O>
*/
public function service(string|Service $name, callable $definition): self;
public function service(Service $name, callable $definition): self;

/**
* @psalm-mutation-free
Expand Down
Loading
Loading