Skip to content

Commit

Permalink
Merge branch 'next' into develop
Browse files Browse the repository at this point in the history
* next:
  shorten expression to build service
  fix readme
  declare the builder immutable
  rename Container to Builder and ServiceLocator to Container
  split responsibility between builder and concrete container
  bump psalm version
  test against lowest dependencies
  require php 8.1
  change email
  use CS 2
  use ramsey/composer-install
  remove bc check
  • Loading branch information
Baptouuuu committed Dec 29, 2022
2 parents 28fa21e + 9d4cc4b commit b60b8b0
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 125 deletions.
74 changes: 19 additions & 55 deletions .github/workflows/ci.yml
Expand Up @@ -3,21 +3,13 @@ name: CI
on: [push]

jobs:
roave_bc_check:
name: Roave BC Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: fetch tags
run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- name: Roave BC Check
uses: docker://nyholm/roave-bc-check-ga
phpunit:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
php-version: ['7.4', '8.0']
php-version: ['8.1', '8.2']
dependencies: ['lowest', 'highest']
name: 'PHPUnit'
steps:
- name: Checkout
Expand All @@ -28,17 +20,10 @@ jobs:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
coverage: none
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
- name: Composer
uses: "ramsey/composer-install@v2"
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install --no-progress
dependency-versions: ${{ matrix.dependencies }}
- name: PHPUnit
run: vendor/bin/phpunit
env:
Expand All @@ -48,7 +33,8 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
php-version: ['7.4', '8.0']
php-version: ['8.1', '8.2']
dependencies: ['lowest', 'highest']
name: 'Coverage'
steps:
- name: Checkout
Expand All @@ -59,17 +45,10 @@ jobs:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
coverage: xdebug
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
- name: Composer
uses: "ramsey/composer-install@v2"
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install --no-progress
dependency-versions: ${{ matrix.dependencies }}
- name: PHPUnit
run: vendor/bin/phpunit --coverage-clover=coverage.clover
env:
Expand All @@ -81,7 +60,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.0']
php-version: ['8.1', '8.2']
dependencies: ['lowest', 'highest']
name: 'Psalm'
steps:
- name: Checkout
Expand All @@ -91,24 +71,17 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
- name: Composer
uses: "ramsey/composer-install@v2"
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install --no-progress
dependency-versions: ${{ matrix.dependencies }}
- name: Psalm
run: vendor/bin/psalm --shepherd
cs:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4']
php-version: ['8.1']
name: 'CS'
steps:
- name: Checkout
Expand All @@ -118,16 +91,7 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-${{ matrix.php-version }}-composer-
- name: Install Dependencies
run: composer install --no-progress
- name: Composer
uses: "ramsey/composer-install@v2"
- name: CS
run: vendor/bin/php-cs-fixer fix --diff --dry-run --diff-format udiff
run: vendor/bin/php-cs-fixer fix --diff --dry-run
File renamed without changes.
13 changes: 7 additions & 6 deletions README.md
@@ -1,4 +1,4 @@
# di
# Dependency Injection

[![Build Status](https://github.com/innmind/di/workflows/CI/badge.svg?branch=master)](https://github.com/innmind/di/actions?query=workflow%3ACI)
[![codecov](https://codecov.io/gh/innmind/di/branch/develop/graph/badge.svg)](https://codecov.io/gh/innmind/di)
Expand All @@ -18,20 +18,21 @@ composer require innmind/di

```php
use Innmind\DI\{
Builder,
Container,
ServiceLocator,
};

$container = (new Container)
->add('connection', fn(ServiceLocator $get) => new ConnectionPool( // imaginary class
$container = Builder::new()
->add('connection', fn(Container $get) => new ConnectionPool( // imaginary class
$get('connection_a'),
$get('connection_b'),
))
->add('connection_a', fn() => new \PDO('mysql://localhost'))
->add('connection_B', fn() => new \PDO('mysql://docker'));
->add('connection_B', fn() => new \PDO('mysql://docker'))
->build();

$connection = $container('connection');
$connection instanceof ConnectionPool; // true
```

The `add` method accepts any `callable` that will return an `object`. This allows to use either anonymus functions for the ease of use (but have a memory impact) or callables of the form `[Service::class, 'factoryMethod']` that allows to only load the class file when the service is loaded.
The `add` method accepts any `callable` that will return an `object`. This allows to use either anonymous functions for the ease of use (but have a memory impact) or callables of the form `[Service::class, 'factoryMethod']` that allows to only load the class file when the service is loaded.
8 changes: 4 additions & 4 deletions composer.json
Expand Up @@ -8,14 +8,14 @@
"authors": [
{
"name": "Baptiste Langlade",
"email": "langlade.baptiste@gmail.com"
"email": "baptiste.langlade@hey.com"
}
],
"support": {
"issues": "http://github.com/innmind/di/issues"
},
"require": {
"php": "~7.4|~8.0"
"php": "~8.1"
},
"autoload": {
"psr-4": {
Expand All @@ -29,8 +29,8 @@
},
"require-dev": {
"phpunit/phpunit": "~9.0",
"vimeo/psalm": "~4.4",
"vimeo/psalm": "~4.30",
"innmind/black-box": "~4.10",
"innmind/coding-standard": "^1.1"
"innmind/coding-standard": "~2.0"
}
}
45 changes: 45 additions & 0 deletions src/Builder.php
@@ -0,0 +1,45 @@
<?php
declare(strict_types = 1);

namespace Innmind\DI;

/**
* @psalm-immutable
*/
final class Builder
{
/** @var array<string, callable(Container): object> */
private array $definitions = [];

/**
* @param array<string, callable(Container): object> $definitions
*/
private function __construct(array $definitions)
{
$this->definitions = $definitions;
}

/**
* @psalm-pure
*/
public static function new(): self
{
return new self([]);
}

/**
* @param callable(Container): object $definition
*/
public function add(string $name, callable $definition): self
{
$definitions = $this->definitions;
$definitions[$name] = $definition;

return new self($definitions);
}

public function build(): Container
{
return Container::of($this->definitions);
}
}
35 changes: 22 additions & 13 deletions src/Container.php
Expand Up @@ -8,15 +8,29 @@
CircularDependency,
};

final class Container implements ServiceLocator
final class Container
{
/** @var array<string, callable(ServiceLocator): object> */
private array $definitions = [];
/** @var array<string, callable(self): object> */
private array $definitions;
/** @var array<string, object> */
private array $services = [];
/** @var list<string> */
private array $building = [];

/**
* @psalm-mutation-free
*
* @param array<string, callable(self): object> $definitions
*/
private function __construct(array $definitions)
{
$this->definitions = $definitions;
}

/**
* @throws ServiceNotFound
* @throws CircularDependency
*/
public function __invoke(string $name): object
{
if (!\array_key_exists($name, $this->definitions)) {
Expand All @@ -34,24 +48,19 @@ public function __invoke(string $name): object
$this->building[] = $name;

try {
return $this->services[$name] ?? $this->services[$name] = ($this->definitions[$name])($this);
return $this->services[$name] ??= ($this->definitions[$name])($this);
} finally {
\array_pop($this->building);
}
}

/**
* This operation is immutable to prevent mixing adding definitions and
* building already defined services.
* @psalm-pure
*
* @param callable(ServiceLocator): object $definition
* @param array<string, callable(self): object> $definitions
*/
public function add(string $name, callable $definition): self
public static function of(array $definitions): self
{
$self = clone $this;
$self->definitions[$name] = $definition;
$self->services = [];

return $self;
return new self($definitions);
}
}
18 changes: 0 additions & 18 deletions src/ServiceLocator.php

This file was deleted.

0 comments on commit b60b8b0

Please sign in to comment.