PHPackages                             popcorn4dinner/commands - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [CLI &amp; Console](/categories/cli)
4. /
5. popcorn4dinner/commands

ActiveLibrary[CLI &amp; Console](/categories/cli)

popcorn4dinner/commands
=======================

An implementation of the command pattern, designed to be used as application layer of an onion architecture based application

0.2.1(8y ago)05MITPHPPHP &gt;=7.1

Since Apr 19Pushed 8y ago1 watchersCompare

[ Source](https://github.com/popcorn4dinner/php-commands)[ Packagist](https://packagist.org/packages/popcorn4dinner/commands)[ RSS](/packages/popcorn4dinner-commands/feed)WikiDiscussions master Synced 4d ago

READMEChangelogDependencies (5)Versions (3)Used By (0)

PHP Commands
============

[](#php-commands)

An opinionated implementation of the command pattern, designed to be used as application layer of an onion architecture based application.

[![./onion_schema.png](./onion_schema.png)](./onion_schema.png)

Installation
------------

[](#installation)

```
composer require popcorn4dinner/commands
```

Usage
-----

[](#usage)

Each action in your application will be represented by 2 classes. The **command** and the **handler**: The **command** represents the input to your action. It’s a simple stateful object containing all data needed to perform the action.

```
class PlaceOrder implements CommandInterface
{
    public $itemId;

    public $placedAt;

    public $price;
}
```

The **handler** is responsible for the flow of performing the action. It makes sure all needed steps are executed in the right order.

```
class PlaceOrderHandler extends AbstractAuthenticatedCommandHandler
{
    /**
     * @param CommandInterface $command
     * @return Order
     * @throws PolicyValidationException
     */
    public function handle(CommandInterface $command, $user = null): Order
    {
        $order = $this->orderFactory->createOrderFor($command->orderItem, $command->placedAt, $user->id)

        if($this->orderValidator->isValid($order, OrderAction::create())){
            $order = $this->orderRepository->create($order);

            $this->paymentGateway->schedulePaymentFor($order->price);

            $this->mailer->sendConfrmationEmailTo($user, $order);
            $this->mailer->sendIncomingOrderNotificationTo($CUSTOMER_SERVICE, $order);

            $this->crm->upload($order);
        }

        return $order;
    }

}
```

### Handler types

[](#handler-types)

This library provides two types of handlers, one to be used within applications that have a user notion (AbstractAuthenticatedCommandHandler), and one for applications without (AbstractCommandHandler). Take a look at the **example folder** for more details.

### Logging

[](#logging)

If you instantiate your handlers with a logger implementing the **Psr/log/LoggerInterface**, every action performed in your application as well as possible failures will be logged automatically.

### Populating Commands

[](#populating-commands)

This library comes with a small helper, that populates command objects for you, if you follow a simple convention.

1. The properties in your command must have the same name as the parameter in your request
2. The name of the request parameters are snake case, the command properties are camel case

Example:

 Command propertyrequest parameter userIduser\_id usernameusername dateOfBirthdate\_of\_birthUsing this helper, can make your controllers wonderfully lean: It’s only responsibility is now to interface between your application and the web.

```
class UserController {

[...]

   public function resetPassword(
        Request $request,
        RequestPasswordResetHandler $handler,
        \Twig_Environment $twig
    )
    {
        if ($request->getMethod() === static::HTTP_GET) {
            return $twig->render('forgot-password.twig');

        } else {
            $command = $this->commandPopulator->populate(new RequestPasswordReset(), $request);
            $user = $handler->handle($command);

            return $twig->render('login.twig', ['message' => 'You will receive an email with reset instructions shortly.']);
        }
    }

}
```

A word on Onion Architecture
----------------------------

[](#a-word-on-onion-architecture)

How I see it, Onion Architecture is essentially one thing: A simplified version of DDD that helps you to keep your easy to read, extend, maintain and reason about. This is a exelent blog post on Onion Architecture that is worth reading:

### Short summary

[](#short-summary)

If you want your application to be an onion, you will essentially distinguish three layers: Infrastructure, Application and Domain. That being said, most of the literature describes a few more or calls them slightly differently. I’m trying to keep this simple, so we will go with the three above.

**The golden rule:** Dependencies are only allowed to go inverts. That means that the everything in the infrastructure is allowed to depend on the application or domain layer, but not the other way around. For this to work, it’s common practice to create interfaces inside your domain that determine the contract with the infrastructure you want to use. At the same time, it allows you to replace databases, filesystems and even frameworks on the fly, without the important part of your application to be effected. You can even think of scenarios, where, for testing, you want to use an in-memory database instead of running an sql server, or write emails to files instead of sending them. Following **Onion Architecture**, those things are no problem at all.

[![./onion_schema.png](./onion_schema.png)](./onion_schema.png)

Imagine we were designing a micro service that allows placing orders in a online shop…

#### Infrastructure

[](#infrastructure)

The **infrastructure** layer of your onion contains things like the UI, Repositories to communicate with Databases, Filesystems, etc. If you are using an MVC frameworks, this is part of your **infrastructure layer** as well.

#### Application

[](#application)

Here is, where I use this library. The **application layer** is responsible for the flow of your application. It’s where you determine which steps have to be performed in which order. Take an incoming order as an example:

```
class PlaceOrderHandler extends AbstractAuthenticatedCommandHandler
{
    /**
     * @param CommandInterface $command
     * @return Order
     * @throws PolicyValidationException
     */
    public function handle(CommandInterface $command, $user = null): Order
    {
        $order = $this->orderFactory->createOrderFor($command->orderItem, $command->placedAt, $user->id)

        if($this->orderValidator->isValid($order, OrderAction::create())){
            $order = $this->orderRepository->create($order);

            $this->paymentGateway->schedulePaymentFor($order->price);

            $this->mailer->sendConfrmationEmailTo($user, $order);
            $this->mailer->sendIncomingOrderNotificationTo(static::CUSTOMER_SERVICE, $order);

            $this->crm->upload($order);
        }

        return $order;
    }

}
```

#### Domain

[](#domain)

Your main domain model in this example would probably be an **order**. Part of your **domain** would also be all the knowledge about what an order has to look like and how to communicate with external services like **payment gateways** and **APIs of your logistics partner** In our example, you would probably find classes like there:

- Order
- OrderAction
- OrderValidator
- OrderRepositoryInterface
- MailerInterface
- PaymentGatewayInterface
- CrmInterface

###  Health Score

22

—

LowBetter than 22% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community4

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

2949d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b7f09c6677ed6fffa796df715c75bba02176e7329794b01059d5f73fdcec295c?d=identicon)[popcorn4dinner](/maintainers/popcorn4dinner)

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/popcorn4dinner-commands/health.svg)

```
[![Health](https://phpackages.com/badges/popcorn4dinner-commands/health.svg)](https://phpackages.com/packages/popcorn4dinner-commands)
```

###  Alternatives

[league/climate

PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.

1.9k14.0M273](/packages/league-climate)[humbug/box

Fast, zero config application bundler with PHARs.

1.3k801.5k69](/packages/humbug-box)[crunzphp/crunz

Schedule your tasks right from the code.

2292.0M6](/packages/crunzphp-crunz)[elgg/elgg

Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.

1.7k15.7k5](/packages/elgg-elgg)[vanilla/garden-cli

A full-featured, yet ridiculously simple commandline parser for your next php cli script. Stop fighting with getopt().

1171.2M43](/packages/vanilla-garden-cli)[mahocommerce/maho

Free and open source ecommerce platform, created in 2024 on the M1 platform, PHP 8.3+

1322.1k12](/packages/mahocommerce-maho)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
