Ain’t gonna need the Symfony bundle!

Often we think a bundle is the solution to our problems and we try hard to fit it into our app. Then developing an app becomes developing hacks to work around things extra-nous to our domain into our domain forcefully or as some could say “cleverly”.

Screenshot 2014-09-04 10.37.44

Lately I did a PR to a repo of an angularjs and RESTful implementation with the FOSRest libraries from symfony. But then I got this response to my PR:

Screenshot 2014-09-04 10.48.19
https://github.com/bayne/symfony-angular-todomvc/pull/1

So to try to prove the point of keeping it simple I went ahead and discovered some nice features from heroku. It will become certainly one of the tools i use if I can pay for it since development is faster, compilation is faster, everything is faster, even I am thinking running jolici or running tests suite in heroku if possible.

I had to use the buildpack for php from @chh and you can literally build the app clicking your iphone.

+        },
+        "heroku": {
+            "framework": "symfony2",
+            "compile": [
+                "cd web; ./../node_modules/.bin/bower install"
+            ]

This thing that was the big reason why plugging a bundle to plug composer hooks was a simple line of code added to the composer thanks to the buildpack. Everything else went quickly in the flow using bower.io and just the tools we know about.

Check the app, I can’t believe it is so easy 🙂

http://here-quick-cordoval-3.herokuapp.com/#/

Now you can PR and show it is working with one click:

Screenshot 2014-09-04 11.30.45

Enjoy!

Doctrine Simple Mapping and Repository Compiler Pass

Recently I stumble upon some doctrine repository definition situation where there were many definitions of custom doctrine repositories. Instead of having a long list over and over of a custom doctrine service definition I started to look at simpler ways this can be just done and let that adapt within a compiler pass and be customized further down the road as much specific to the application as possible.

I checked out https://github.com/mmoreram/SimpleDoctrineMapping and even though this package seems to be interesting to simplify the auto-mapping in some way I wanted to really have a way to do the simplification not for the mapping of the entities but for the custom repository service definitions. One good thing about this library is that is not a bundle! yey!

So I ended up with just passing an array of parameters, with keys being the model classes, and the values being the repository fqcn’s.

<?php
 
namespace Vendor\Package\DependencyInjection\Compiler;
 
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
 
class CustomRepositoryPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        foreach ($container->getParameter('repositories') as $model => $class) {
            $definition = new Definition();
            $definition
                ->setClass($class)
                ->setArguments([$model])
                ->setFactoryMethod('getRepository')
                ->setFactoryService('doctrine')
                ->setPublic(true)
                ->setLazy(true)
            ;
 
            $container->setDefinition(
                'vendor.repository.'.$this->slug($class),
                $definition
            );
        }
    }
 
    private function slug($fqcn)
    {
        $fqcn = str_replace('Repository', '', $fqcn);
        $names = explode('\\', $fqcn);
        $string = end($names);
        $string = preg_replace('/([A-Z])/', '_$1', $string);
 
        return strtolower(substr($string,1));
    }
}

This as a first approach is simple and straight to the point. Now my 100’s of lines on service definitions for custom repositories were downed to just specifying the key value pairs as parameters:

parameters:
    repositories:
        Vendor\Package\Model\Action: Vendor\Package\Repository\ActionRepository
        Vendor\Package\Model\Tenant: Vendor\Package\Repository\TenantRepository
        // ...

This compiler pass can be used as i have shown in previous posts without the need of a bundle fortunately! And it can be further taylor to meet the domain needs of your domain packages.

Although in early stage I just wanted to put it out so it could benefit someone with the same problem. Take it just as an initial idea and then improve upon it like I am doing in other projects.

Encouragements, thanks for reading. Appreciated!

Code Nuances, Important to Who Hears/Reads

This is a long promised post.

Let’s start.

What is wrong with the following picture?

$subject        = $actionManager->findOrCreateComponent($user);
$someMorelonger = $actionManager->execute($subject);

First, the brain look for differences to understand what is being written. You don’t see a book aligning their similar *Howevers* across pages. What you see is in a poem the font is well taken care and the procedures administered to markup based on syntax.
Aligning equals in this case makes it harder to maintain. Suppose you add a third line, that has a longer property name, now you need to change three lines instead of one. Makes no sense right?

Second, the brain works reading from left to right and from top down. You don’t gain anything by indenting weirdly spaces like this before an equal sign. It is code, poetry, not a senseless computer matrix.

The other example aligned with this mindset is. What happens when the word is too long like here:

    "phpunit/phpunit":                      "~4.1.4",
    "matthiasnoback/symfony-service-definition-validator": "~1.2.0",
    "raulfraile/ladybug": "~1.0.8"

All plot to have neatly aligned versions is thrown to the trash can! Just don’t waste time doing this is my advice.

Let’s see another of this well known hassles:

<?php
 
namespace Bafford\PasswordStrengthBundle\Validator\Constraints;
 
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
 
class PasswordStrengthValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        if($value === null)
            $value = '';
 
        if($constraint->minLength > 0 && (strlen($value) < $constraint->minLength))
            $this->context->addViolation($constraint->tooShortMessage, array('{{length}}' => $constraint->minLength));
 
        if($constraint->requireLetters && !preg_match('/\pL/', $value))
            $this->context->addViolation($constraint->missingLettersMessage);
 
        if($constraint->requireCaseDiff && !preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/', $value))
            $this->context->addViolation($constraint->requireCaseDiffMessage);
 
        if($constraint->requireNumbers && !preg_match('/\pN/', $value))
            $this->context->addViolation($constraint->missingNumbersMessage);
    }
}

This time in a known password strength bundle. Notice the hassle in maintaining these conditional without braces. It just makes it harder to read and maintain. If one makes a mistake there, hunting the bug could be very tedious and cryptic.

The importance of use for a cs fixer tool cannot be underestimated. For a code that is changing continually, error prone, introducing an error happens at a fast rate. Therefore we should be more careful and integrate the fixer into the cycle.

Picture now simple code turned into a nightmare:

function it_does_the_job();

Into:

/**
 * It does the job.
 * It does some very complicated stuff, but gets the job done.
 *
 * @author Luis Cordova <cordoval@gmail.com>
 * @author Some other author <etc@gmail.com>
 * @package my package
 * @license MIT
 *
 * @param void
 * @return void
 */
public function it_does_the_job();

It just does not make sense when git and services like github et al help us find who did what in a project.

Let’s jump to another nuance, this time is getting into the custom of locking the composer to 3 digits. Some people do:

"jms/di-extra-bundle": "1.4.*",
"jms/aop-bundle": "1.0.*"

Instead of:

"jms/di-extra-bundle": "1.4.1",
"jms/aop-bundle": "1.0.1"

Or similar. The thing is sometimes when they just do 1.4 or ~1.4 some have the wrong idea. You should read this https://igor.io/2013/01/07/composer-versioning.html. However an improvement on top of it is the custom to specify 3 numbers like in:

"jms/di-extra-bundle": "~1.4.1",

This is a better practice since it allows only the minor number to sweep. It does not leave any doubt as to which number is flexible and helps avoiding some undesired scenarios like:

Hm, why 2.2.1 are older then 2.1 ?
I use this format in composer
 
"apy/datagrid-bundle": "~2.1"
And i have 2.2.1 version

:), then you wonder!

There are more nuances but i am shipping this blog to help today rather than later!

Elcodi Ecommerce Going Components (Symfony-based): Review and Startup your store!

Sometime ago I wrote a book on Symfony Ecommerce at http://pilotci.com. This blog post expands to cover a solution that has taken a good decision lately. The decision of Elcodi to go components. This is packages, somewhat decoupled at first but aiming to more decoupled type packages.

The quick way to see how a store can be put together with Elcodi components is by clonning its flag store https://github.com/elcodi/bamboo-store:

git clone git@github.com:elcodi/bamboo-store.git
cd bamboo-store
composer install

You will need my PR https://github.com/elcodi/bamboo-store/pull/29 to get the right dependencies and the basic store working.

Also you will need this https://github.com/elcodi/elcodi/pull/252/files. Because there is an error when the database is not setup and the command is set as a service.

After running creating the database and schema and running the fixtures:

~ php app/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue Y/N ?y
  > purging database
  > loading Elcodi\Bundle\LanguageBundle\DataFixtures\ORM\LanguageData
  > loading Elcodi\Bundle\AttributeBundle\DataFixtures\ORM\AttributeData
  > loading Elcodi\Bundle\RuleBundle\DataFixtures\ORM\ExpressionData
  > loading Elcodi\Bundle\MenuBundle\DataFixtures\ORM\NodeData
  > loading Elcodi\Bundle\UserBundle\DataFixtures\ORM\CustomerData
  > loading Elcodi\Bundle\BannerBundle\DataFixtures\ORM\BannerZoneData
  > loading Elcodi\Bundle\CurrencyBundle\DataFixtures\ORM\CurrencyData
  > loading Elcodi\Bundle\ProductBundle\DataFixtures\ORM\CategoryData
  > loading Elcodi\Bundle\ProductBundle\DataFixtures\ORM\ManufacturerData
  > loading Elcodi\Bundle\ProductBundle\DataFixtures\ORM\ProductData
  > loading Elcodi\Bundle\CartBundle\DataFixtures\ORM\CartData
  > loading Elcodi\Bundle\CouponBundle\DataFixtures\ORM\CouponData
  > loading Elcodi\Bundle\CartCouponBundle\DataFixtures\ORM\CartCouponData
  > loading Elcodi\Bundle\BannerBundle\DataFixtures\ORM\BannerData
  > loading Elcodi\Bundle\CurrencyBundle\DataFixtures\ORM\RatesData
  > loading Elcodi\Bundle\AttributeBundle\DataFixtures\ORM\ValueData
  > loading Elcodi\Bundle\ProductBundle\DataFixtures\ORM\VariantData
  > loading Elcodi\Bundle\RuleBundle\DataFixtures\ORM\RuleData
  > loading Elcodi\Bundle\RuleBundle\DataFixtures\ORM\RuleGroupData
  > loading Elcodi\Bundle\MenuBundle\DataFixtures\ORM\MenuData

You can see the store with php -S localhost:8000 -t web. And opening the browser on app_dev.php.

Screenshot 2014-08-28 18.57.30

The construction of the store is very simple and even though we can improve removing the nightmare of annotations, it seems like the power of the services is the real meat there:

    /**
     * Cart view
     *
     * @param FormView      $formView Form view
     * @param CartInterface $cart     Cart
     *
     * @return array
     *
     * @Route(
     *      path = "",
     *      name = "store_cart_view"
     * )
     * @Method("GET")
     * @Template
     *
     * @AnnotationEntity(
     *      class = {
     *          "factory" = "elcodi.cart_wrapper",
     *          "method" = "loadCart",
     *          "static" = false,
     *      },
     *      name = "cart"
     * )
     * @AnnotationForm(
     *      class = "store_cart_form_type_cart",
     *      name  = "formView",
     *      entity = "cart",
     * )
     */
    public function viewAction(
        FormView $formView,
        CartInterface $cart
    )
    {
        $relatedProducts = [];
 
        if ($cart->getCartLines()->count()) {
 
            $relatedProducts = $this
                ->get('store.product.service.product_collection_provider')
                ->getRelatedProducts($cart
                        ->getCartLines()
                        ->first()
                        ->getProduct()
                    , 3);
        }
 
        $cartCoupons = $this
            ->get('elcodi.cart_coupon_manager')
            ->getCartCoupons($cart);
 
        return [
            'cart'             => $cart,
            'cartcoupon'       => $cartCoupons,
            'form'             => $formView,
            'related_products' => $relatedProducts
        ];
    }

The annotations are basically boilerplate code for param converters and getting the form sorted out. All in all, it is spread out in various endpoints/links that do the work of the store. In the end is a clean simple store solution that does not get on the way. If you don’t understand or a component does not fit certain needs you can obliterate it by just unplugging the respective bundle. This latter of course can be further improved defining compiler passes in a respective package so that we can forget about bundles once and for all as it is the trend of modern developments.

The good thing is it is an open source project. I have seen various frameworks, sylius, vespolina, thelia, leaphly, akeneo and others, my advise is always to strive for simplicity and less strings attached. Readability of code is paramount because you cannot design with something you disagree with or cannot read very well. Just to name a few, vespolina is a bit dead, thelia is one unit and not exactly components, leaphly misses a bit of other components, and akeneo is more a backend, and sylius well it follows a similar approach to Elcodi and it has been for a bit longer but it is a bit hard to chew and challenging to implement features consistently with a different approach sometimes. All have pros and cons, but the idea of a good ecommerce is one does not get on the way, your app will be domain driven and so the components should just support your design not the other way around.

Next steps, homework, is to probably get rid of the annotations of the top layer in Elcodi bamboo and see how to make that more streamlined.

Hope you try elcodi!

New Symfony Way: Scratch Bundle for Packages with Compiler Passes

In the same way silex have service providers you can also have the same in Symfony, no need for bundles to define services. You can just plug some compiler passes and special configuration classes but really there is no need to create a bundle to have configuration capabilities.

The reasons for not having any bundle is that there is really no need for a bundle when you are creating an application package. Creating a bundle pulls your direction away from creating a reusable package outside symfony whereas if you create a standalone package and offer some service definitions it ends up being a better choice.

The addon which i have not mentioned is that there are really good projects out there like PageKit, even yucky projects like laravel that use symfony components or even others that do use the config and di components and yet do not use the bundle concept. For them the world of bundles is far away and will never be reached. Whereas if you design a library/package standalone it can have providers for these too. The end result is more reusability.

Let’s start with a good example. At the end of this blog from Matthias Noback’s blog post we have learned how to register ancillary event dispatcher services that are decoupled from the symfony default event_dispatcher system and how we register listeners or subscribers with that sub event system.

Here is the same code showing how you register the compiler pass in the way proposed in that blog post:

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
 
class YourBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(
            new RegisterListenersPass(
                'domain_event_dispatcher',
                'domain_event_listener',
                'domain_event_subscriber'
            ),
            PassConfig::TYPE_BEFORE_REMOVING
        );
    }
}

and add the service definitions:

services:
    domain_event_dispatcher:
        class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
        arguments:
            - @service_container

And how you create a listener (and extra bonus for the subscriber):

services:
    some_domain_event_listener
        class: ...
        tags:
            -
                name: domain_event_listener
                event: my_domain_event
                method: onMyDomainEvent
    some_domain_event_subscriber
        class: ...
        tags:
            -
                name: domain_event_subscriber

There is I believe another way to do this. What is truly required is a way to plug directly into the kernel (like it is done in bundles), the compiler passes that create this service definitions and then be done with it.

Let’s take a stab. First we can modify generically our AppKernel.php like this:

    protected function prepareContainer(ContainerBuilder $container)
    {
        $extensions = array();
        foreach ($this->bundles as $bundle) {
            if ($extension = $bundle->getContainerExtension()) {
                $container->registerExtension($extension);
                $extensions[] = $extension->getAlias();
            }
 
            if ($this->debug) {
                $container->addObjectResource($bundle);
            }
        }
        foreach ($this->bundles as $bundle) {
            $bundle->build($container);
        }
 
        $this->hookCompilers($container);
 
        // ensure these extensions are implicitly loaded
        $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
    }

Notice the hookCompilers is a custom method added:

    private function hookCompilers(ContainerBuilder $container)
    {
        foreach ($this->registerCompilers() as $compilerRow) {
            $instance = $compilerRow[0];
            $type = $compilerRow[1];
            $debug = $compilerRow[2];
            if (!$debug || $container->getParameter('kernel.debug')) {
                $container->addCompilerPass($instance, $type);
            }
        }
    }

But that will not need to change. The registerCompilers method is equivalent to the registerBundles method that is well known by the bundle system users. This registerCompilers method will look like:

    public function registerCompilers()
    {
        $configuration = new Configuration();
        $configuration->setEvaluateExpressions(true);
 
        return [
            [new ValidateServiceDefinitionsPass($configuration), PassConfig::TYPE_AFTER_REMOVING, true],
            [new FixValidatorDefinitionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, true],
            [new RegisterListenersPass(Dispatchers::READ, Dispatchers::READ_LISTENER, Dispatchers::READ_SUBSCRIBER), PassConfig::TYPE_BEFORE_REMOVING, false],
            [new RegisterListenersPass(Dispatchers::WRITE, Dispatchers::WRITE_LISTENER, Dispatchers::WRITE_SUBSCRIBER), PassConfig::TYPE_BEFORE_REMOVING, false],
        ];
    }

Notice that we have added several compiler passes here. The first two are coming from the package for validating the service definitions and stuff that we saw in a previous post. Now though they are totally standardized. The 2 last compiler passes added are two new event sub systems, easily pluggable just by adding new rows here. After this tapping into a different event dispatcher is totally straightforward.

Mind that we have just compiled the constants into a class Dispatchers.php:

<?php
 
namespace Grace;
 
class Dispatchers
{
    const READ = 'read_event_dispatcher';
    const READ_LISTENER = 'read_event_dispatcher_listener';
    const READ_SUBSCRIBER = 'read_event_dispatcher_subscriber';
 
    const WRITE = 'write_event_dispatcher';
    const WRITE_LISTENER = 'write_event_dispatcher_listener';
    const WRITE_SUBSCRIBER = 'write_event_dispatcher_subscriber';
}

You can now just define a subscriber like:

    grace.some_domain_event_subscriber:
        class: Grace\ExampleSubscriber
        tags:
            -
                name: Grace\Dispatchers::READ_SUBSCRIBER

The whole story can be better seen in a diff of this PR in matthew-7-12 project https://github.com/cordoval/matthew-7-12/pull/70/files.

A note on the logging capability of these new event dispatcher sub systems was made by @sstok. The concern is that on debug mode the event dispatcher is actually wrapped like this:

        <service id="debug.event_dispatcher" class="%debug.event_dispatcher.class%">
            <tag name="monolog.logger" channel="event" />
            <argument type="service" id="debug.event_dispatcher.parent" />
            <argument type="service" id="debug.stopwatch" />
            <argument type="service" id="logger" on-invalid="null" />
        </service>

Perhaps we can do a conditional and check for the interface they extend or class of the event dispatcher base that they extend and decorate accordingly our dispatchers too in case we are under the development mode. This of course is not hard to do and it could be accomplished by a DecorateRegisterListenerPasses.php compiler pass too.

An also good example on how to split a bundle and a dependency injection provider package is https://github.com/rollerworks/RollerworksSearchBundle. This bundle actually requires its dependency extension component in its composer.json:

    "require": {
        "php": ">=5.3.3",
        "rollerworks/search-symfony-di": "1.*@dev",
        "symfony/framework-bundle": "~2.1",
        "symfony/finder": "~2.1"
    },

Offering very good separation for those who integrate Rollerworks Search package without having to be tied to use a bundle. This is a better approach than the bundle one. You can take a look at the package here https://github.com/rollerworks/rollerworks-search-symfony-di/tree/master/src. In there you can also see a custom loader which is nice for when you go all the way with a bundle-less approach.

This approach will do great good to those systems that only use some symfony components and yet leverage their own component subsystem. Also for those projects that require flexibility, especially when dealing with DDD this is a desirable architecture to pursue.

Hope you like the approach, comment and don’t forget to retweet sil vous plait!