Skip to content

Commit

Permalink
Merge 93027cb into 6eb8a8d
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-gribanov committed Jan 22, 2020
2 parents 6eb8a8d + 93027cb commit 360ea25
Show file tree
Hide file tree
Showing 78 changed files with 1,569 additions and 501 deletions.
8 changes: 8 additions & 0 deletions .php_cs.dist
@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);

$header = <<<EOF
GpsLab component.
Expand All @@ -21,10 +22,17 @@ return PhpCsFixer\Config::create()
'class_definition' => [
'multiLineExtendsEachSingleLine' => true,
],
'no_superfluous_phpdoc_tags' => false,
'blank_line_after_opening_tag' => false,
'phpdoc_no_empty_return' => false,
'ordered_imports' => [
'sort_algorithm' => 'alpha',
],
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->notPath('bootstrap.php')
)
;
3 changes: 3 additions & 0 deletions .styleci.yml
Expand Up @@ -2,6 +2,9 @@ preset: symfony

enabled:
- short_array_syntax
- alpha_ordered_imports

disabled:
- phpdoc_align
- blank_line_after_opening_tag
- phpdoc_no_empty_return
38 changes: 21 additions & 17 deletions .travis.yml
Expand Up @@ -12,45 +12,49 @@ branches:
matrix:
fast_finish: true
include:
- php: 7.4
- php: 7.3
- php: 7.2
- php: 7.1
- php: 7.0
- php: 5.6
- php: 5.5
dist: trusty
- php: 5.5
- php: 7.1
dist: trusty
env: SYMFONY_VERSION=2.7.*
- php: 5.5
- php: 7.1
dist: trusty
env: SYMFONY_VERSION=2.8.*
- php: 5.5
- php: 7.1
dist: trusty
env: SYMFONY_VERSION=3.4.*
- php: 7.1
dist: trusty
env: SYMFONY_VERSION=3.0.*
- php: 5.5
env: SYMFONY_VERSION=4.4.*
- php: 7.2
dist: trusty
env: SYMFONY_VERSION=5.0.*
- php: 7.1
dist: trusty
env: PREDIS_VERSION=1.0.*
- php: 5.5
- php: 7.1
dist: trusty
env: PREDIS_VERSION=1.1.*
- php: 5.6
env: PUBSUB_PREDIS_VERSION=2.0.* COVERALLS=1

before_install:
- if [ "$TRAVIS_PHP_VERSION" = "hhvm" ]; then echo 'xdebug.enable = on' >> /etc/hhvm/php.ini; fi
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
- wget https://scrutinizer-ci.com/ocular.phar
- wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.2.0/php-coveralls.phar

install:
- if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --dev --no-update; fi;
- if [ "$PREDIS_VERSION" != "" ]; then composer require "predis/predis:${PREDIS_VERSION}" --dev --no-update; fi;
- if [ "$PUBSUB_PREDIS_VERSION" != "" ]; then composer require "superbalist/php-pubsub-redis:${PUBSUB_PREDIS_VERSION}" --dev --no-update; fi;
- composer install --prefer-dist --no-interaction --no-scripts --no-progress
# Predis client in version 1.0 is not iterable
- if [ "$PREDIS_VERSION" = "1.0.*" ]; then cp .travis/predis_10_phpstan.neon phpstan.neon; fi;

script:
- if [ "$COVERALLS" != "1" ]; then vendor/bin/phpunit --verbose; fi;
- if [ "$COVERALLS" = "1" ]; then vendor/bin/phpunit --verbose --coverage-clover build/coverage-clover.xml; fi;
- vendor/bin/phpunit --verbose --coverage-clover build/coverage-clover.xml
- vendor/bin/phpstan analyse

after_script:
- if [ "$COVERALLS" = "1" ]; then vendor/bin/ocular code-coverage:upload --format=php-clover build/coverage-clover.xml; fi;
- if [ "$COVERALLS" = "1" ]; then vendor/bin/coveralls -v -c .coveralls.yml; fi;
- php ocular.phar code-coverage:upload --format=php-clover build/coverage-clover.xml
- php php-coveralls.phar -v -c .coveralls.yml
6 changes: 6 additions & 0 deletions .travis/predis_10_phpstan.neon
@@ -0,0 +1,6 @@
includes:
- phpstan.neon.dist

parameters:
ignoreErrors:
- '#Predis\\Client<Predis\\Client>#'
160 changes: 158 additions & 2 deletions README.md
Expand Up @@ -27,7 +27,7 @@ composer require gpslab/cqrs
* [Bus](docs/command/command_bus.md)
* Handler
* [Create handler](docs/command/handler.md)
* Locator
* Locator and Subscribers
* [Direct binding locator](docs/command/locator/direct_binding.md)
* [PSR-11 Container locator](docs/command/locator/psr-11_container.md) *([PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md))*
* [Symfony container locator](docs/command/locator/symfony_container.md) *(Symfony 3.3 [implements](http://symfony.com/blog/new-in-symfony-3-3-psr-11-containers) a [PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md))*
Expand All @@ -46,20 +46,176 @@ composer require gpslab/cqrs
* [Middleware](https://github.com/gpslab/middleware)
* [Payload](https://github.com/gpslab/payload)

### Simple usage commands

Commands, in the [CQRS](https://martinfowler.com/bliki/CQRS.html) approach, are designed to change the data in the
application.

For example, consider the procedure for renaming an article.

Create a command to rename:

```php
use GpsLab\Component\Command\Command;

class RenameArticleCommand implements Command
{
public $article_id;

public $new_name = '';
}
```

> **Note**
>
> To simplify the filling of the command, you can use [payload](https://github.com/gpslab/payload).
You can use any implementations of [callable type](http://php.net/manual/en/language.types.callable.php) as a command
handler. We recommend using public methods of classes as handlers. For example we use [Doctrine ORM](https://github.com/doctrine/doctrine2).

```php
use GpsLab\Component\Command\Command;
use Doctrine\ORM\EntityManagerInterface;

class RenameArticleHandler
{
private $em;

public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}

public function handleRenameArticle(RenameArticleCommand $command): void
{
// get article by id
$article = $this->em->getRepository(Article::class)->find($command->article_id);
$article->rename($command->new_name);
}
}
```

And now we register handler and handle command.

```php
use GpsLab\Component\Command\Bus\HandlerLocatedCommandBus;
use GpsLab\Component\Command\Handler\Locator\DirectBindingCommandHandlerLocator;

// register command handler in handler locator
$handler = new RenameArticleHandler($em);
$locator = new DirectBindingCommandHandlerLocator();
$locator->registerHandler(RenameArticleCommand::class, [$handler, 'handleRenameArticle']);

// create bus with command handler locator
$bus = new HandlerLocatedCommandBus($locator);

// ...

// create rename article command
$command = new RenameArticleCommand();
$command->article_id = $article_id;
$command->new_name = $new_name;

// handle command
$bus->handle($command);
```

For the asynchronous handle a command you can use `CommandQueue`.

> **Note**
>
> To monitor the execution of commands, you can use [middleware](https://github.com/gpslab/middleware).

## Query

* **[Simple usage](docs/query/simple_usage.md)**
* [Bus](docs/query/query_bus.md)
* Handler
* [Create handler](docs/query/handler.md)
* Locator
* Locator and Subscribers
* [Direct binding locator](docs/query/locator/direct_binding.md)
* [PSR-11 Container locator](docs/query/locator/psr-11_container.md) *([PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md))*
* [Symfony container locator](docs/query/locator/symfony_container.md) *(Symfony 3.3 [implements](http://symfony.com/blog/new-in-symfony-3-3-psr-11-containers) a [PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md))*
* [Middleware](https://github.com/gpslab/middleware)
* [Payload](https://github.com/gpslab/payload)
* [Doctrine specification query](https://github.com/gpslab/specification-query)

### Simple usage queries

Query, in the [CQRS](https://martinfowler.com/bliki/CQRS.html) approach, are designed to get the data in the
application.

For example, consider the procedure for get an article by identity.

Create a query:

```php
use GpsLab\Component\Query\Query;

class ArticleByIdentityQuery implements Query
{
public $article_id;
}
```

> **Note**
>
> To simplify the filling of the query, you can use [payload](https://github.com/gpslab/payload).
You can use any implementations of [callable type](http://php.net/manual/en/language.types.callable.php) as a query
handler. We recommend using public methods of classes as handlers. For example we use [Doctrine ORM](https://github.com/doctrine/doctrine2).

```php
use GpsLab\Component\Query\Query;
use Doctrine\ORM\EntityManagerInterface;

class ArticleByIdentityHandler
{
private $em;

public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}

public function handleArticleByIdentity(ArticleByIdentityQuery $query)
{
// get article by id
return $this->em->getRepository(Article::class)->find($query->article_id);
}
}
```

And now we register handler and handle query.

```php
use GpsLab\Component\Query\Bus\HandlerLocatedQueryBus;
use GpsLab\Component\Query\Handler\Locator\DirectBindingQueryHandlerLocator;

// register query handler in handler locator
$handler = new ArticleByIdentityHandler($em);
$locator = new DirectBindingQueryHandlerLocator();
$locator->registerHandler(ArticleByIdentityQuery::class, [$handler, 'handleArticleByIdentity']);

// create bus with query handler locator
$bus = new HandlerLocatedQueryBus($locator);

// ...

// create find article query
$query = new ArticleByIdentityQuery();
$query->article_id = $article_id;

// handle query
$article = $bus->handle($query);
```

> **Note**
>
> To monitor the execution of commands, you can use [middleware](https://github.com/gpslab/middleware).

## License

This bundle is under the [MIT license](http://opensource.org/licenses/MIT). See the complete license in the file: LICENSE
13 changes: 7 additions & 6 deletions composer.json
Expand Up @@ -23,16 +23,17 @@
}
},
"require": {
"php": ">=5.5.0"
"php": ">=7.1.0"
},
"require-dev": {
"psr/container": "~1.0",
"psr/log": "~1.0",
"symfony/dependency-injection": "~2.3|~3.0",
"symfony/serializer": "~2.3|~3.0",
"symfony/dependency-injection": "~2.3|~3.0|~4.0|~5.0",
"symfony/serializer": "~2.3|~3.0|~4.0|~5.0",
"predis/predis": "~1.0|~1.1",
"phpunit/phpunit": "^4.8.36",
"scrutinizer/ocular": "~1.3",
"php-coveralls/php-coveralls": "^1.0"
"phpunit/phpunit": "^7.0|^8.2",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"superbalist/php-pubsub-redis": "2.0.*"
}
}
14 changes: 7 additions & 7 deletions docs/command/handler.md
Expand Up @@ -7,7 +7,7 @@ handler.
The command handler can be a [anonymous function](http://php.net/manual/en/functions.anonymous.php):

```php
$handler = function (RenameArticleCommand $command) {
$handler = static function (RenameArticleCommand $command): void {
// do something
};

Expand All @@ -19,7 +19,7 @@ $locator->registerHandler(RenameArticleCommand::class, $handler);
It can be a some function:

```php
function RenameArticleHandler(RenameArticleCommand $command)
function RenameArticleHandler(RenameArticleCommand $command): void
{
// do something
}
Expand All @@ -34,7 +34,7 @@ It can be a [called object](http://php.net/manual/en/language.oop5.magic.php#obj
```php
class RenameArticleHandler
{
public function __invoke(RenameArticleCommand $command)
public function __invoke(RenameArticleCommand $command): void
{
// do something
}
Expand All @@ -50,7 +50,7 @@ It can be a static method of class:
```php
class RenameArticleHandler
{
public static function handleRenameArticle(RenameArticleCommand $command)
public static function handleRenameArticle(RenameArticleCommand $command): void
{
// do something
}
Expand All @@ -66,7 +66,7 @@ It can be a public method of class:
```php
class RenameArticleHandler
{
public function handleRenameArticle(RenameArticleCommand $command)
public function handleRenameArticle(RenameArticleCommand $command): void
{
// do something
}
Expand All @@ -82,12 +82,12 @@ You can handle many commands in one handler.
```php
class ArticleHandler
{
public function handleRenameArticle(RenameArticleCommand $command)
public function handleRenameArticle(RenameArticleCommand $command): void
{
// do something
}

public function handlePublishArticle(PublishArticleCommand $command)
public function handlePublishArticle(PublishArticleCommand $command): void
{
// do something
}
Expand Down

0 comments on commit 360ea25

Please sign in to comment.