About Luis Cordova

description

Arrivederchi Ciao Chau Symfony … Welcome Standalone Dumper & C Extension

You start with requiring the dependency on the component like this:

"patchwork/dumper": "~1.2@dev",

The component also does not get tagged very often so you will need master to get the function twig below explained. You can install it also together with ladybug to compare :).

After adding the above:

"raulfraile/ladybug": "~1.0.8",
"patchwork/dumper": "~1.2@dev",

You can require the bundle from ladybug too if you want for the twig function. You can also plug the dumper twig function plugging the bundle that already comes within the patchwork/dumper:

if ('dev' === $this->getEnvironment()) {
            // ...
            $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
            $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
            // ...
        }

Of course as usual I do not recommend to load bundles. So what I do instead is to plug the twig extension straight to the kernel if possible. Now it is time to focus on the component. After this DebugBundle is plugged you can invoke it from your view too:

The function dumps to the same view the variable var:

{{ dump(var) }}

Where as the dump tag only presents a screenshot in miniature on the symfony WDT (Web Development Toolbar) and waits for you to click there so that it will take you to the sidebar-ed view in white that is also expandable:

{% dump var %}

I fully prefer the dumping directly on the view since it is less time wasted. Also it works the same as in the cli so there is nothing new to learn. I tested side to side to ladybug and I think ladybug still has some information that can get expanded and it is what I am more accustomed to. However ladybug often breaks whereas this component is very solid and integrates nicely with symfony and has a dark background which I like very much.

Some examples borrowed from the PR in symfony follow. Notice the beautiful dumping of the container:

Source: patchwork dumper component on github.

Now a comparison side to side of dump vs var_dump:

Screenshot 2014-09-17 21.20.32 Source: patchwork dumper component on github and my desktop screenshot.

Ladybug colors fall short a bit, but still is a good option. However the reach of the dumper component is way beyond since it comes with a C extension that can be compiled:

 phpize
./configure
make
sudo make install

However honestly until this is easy to install as:

brew install php56-symfony_debug

I will not be able to use it nor I want to use it since I rather fallback to the php implementation.

The view of ladybug is expandable in a nice way:

Source: Github LadybugBundle.

Notice ladybug has also a bundle but I rather don’t use the bundle though sometimes it comes handy for a dump on the view. The thing is I think many other packages would like to use this component totally independent from symfony, however creating a dependency on this will pull several other dependencies right away:

"require": {
        "php": ">=5.3.3",
        "symfony/config": "~2.4",
        "symfony/dependency-injection": "~2.2",
        "symfony/event-dispatcher": "~2.3",
        "symfony/http-kernel": "~2.3"
    },
    "require-dev": {
        "twig/twig": "~1.12"
    },

Really a bunch more since the DI thing and others will be a load of things.

What I think I will use in my projects will be the component but will try to untie as much stuff as possible and wire things with say the aura DI or try at least. The component in itself should just be invokable via:

use Symfony\Component\VarDumper\VarDumper as Dumper;
 
Dumper::dump($var);

And here is the implementation detail:

    public static function dump($var)
    {
        if (null === self::$handler) {
            $cloner = extension_loaded('symfony_debug') ? new ExtCloner() : new PhpCloner();
            $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();
            self::$handler = function ($var) use ($cloner, $dumper) {
                $dumper->dump($cloner->cloneVar($var));
            };
        }
 
        return call_user_func(self::$handler, $var);
    }
 
    public static function setHandler($callable)
    {
        if (null !== $callable && !is_callable($callable, true)) {
            throw new \InvalidArgumentException('Invalid PHP callback.');
        }
 
        $prevHandler = self::$handler;
        self::$handler = $callable;
 
        return $prevHandler;
    }

Let the reader understand a bit. Basically it uses a cloner within the handler that gets called finally to dump the variable $var. It switches between the html or cli dumpers accordingly. And depending on if the C extension is preloaded it will choose the respective XCloner::class. The high level handler callable will use the respective implementations to do the final job invoking each.

That is it! So before 2.6, even now you can take advantage of this nice component and plug it into your say AuraPHP project or other. It will rock and you will not have to wait for 2.6 release nor for the big merge of the PR that smashes it into the whole of bulk of symfony/symfony.

If someone plugs the C extension on brew please let me know!

Look Mama: No Console Coupling! Bye Symfony, Welcome Aura Cli!

First don’t loose sight of the Dependency Injection part on any project! This is the tip of the iceberg. If you have buried it under the gravel of a foreign abstraction or a framework imposed layer, then beware! you are loosing a bit of control that may be dangerous for decoupling. The best thing is when the DI and other components are truly decoupled. Your services are meant to be decoupled that is what makes DI great! If that is not the case then blame your framework in the full sense of the word.

Let me give you a clear example. Let me show you how we can build an easy decoupled console app with only 3 dependencies that are completely decoupled.

Suppose in our composer.json we require a DI, a cli component that has support to extract the context values from the prompt, and a dispatcher so we can decouple this first step of extraction with the actual implementation of services which will be each command. Welcome to AuraPHP 2.0 components!

    "require": {
        "aura/di": "2.*@dev",
        "aura/cli": "2.*@dev",
        "aura/dispatcher": "2.*@dev"
    },

Let’s now start sketching our console.php script:

<?php
 
use Aura\Di\ContainerBuilder;
use Cordoval\Console\Config;
use Cordoval\Console\Runner;
 
require __DIR__.'/vendor/autoload.php';
 
exit((new ContainerBuilder())
    ->newInstance([], [Config::class])
    ->newInstance(Runner::class)
    ->run()
);

Yes, it is very simple and looks beautiful. Let’s explain what is happening under the hood. Remember I said to keep DI layer the top one by any means? Well that is the container!

To build the services inside our container we pass a Config class where we define our services using the DI component:

<?php
 
namespace Cordoval\Console;
 
use Aura\Cli\_Config\Common;
use Aura\Cli\Context;
use Aura\Cli\Stdio;
use Aura\Di\Container;
use Aura\Dispatcher\Dispatcher;
use Cordoval\Console\Task\Help;
 
class Config extends Common
{
    public function define(Container $di)
    {
        parent::define($di);
 
        $di->set('cordoval:stdio', $di->lazyNew(Stdio::class));
        $di->set('cordoval:context', $di->lazyNew(Context::class));
        $di->set(
            'cordoval:dispatcher',
            $di->lazyNew(Dispatcher::class, ['object_param' => 'command'])
        );
 
        $di->params[Runner::class] = [
            'dispatcher' => $di->lazyGet('cordoval:dispatcher'),
            'context' => $di->lazyGet('cordoval:context'),
        ];
 
        $di->params[Help::class] = [
            'context' => $di->lazyGet('cordoval:context'),
            'stdio' => $di->lazyGet('cordoval:stdio'),
        ];
    }
 
    public function modify(Container $di)
    {
        $di->get('cordoval:dispatcher')
            ->setObject('help', $di->lazyNew(Help::class))
        ;
    }
}

Notice the beauty of service definition and lazy loading. The first method is called first before freezing the container. Then it is all about modifying services. The base class from which we extend defines the basic building blocks from the global variables. This is the context information and is important for the cli operation.

<?php
namespace Aura\Cli\_Config;
 
use Aura\Di\Config;
use Aura\Di\Container;
 
class Common extends Config
{
    public function define(Container $di)
    {
        /**
         * Aura\Cli\Context\Argv
         */
        $di->params['Aura\Cli\Context\Argv'] = array(
            'values' => (isset($_SERVER['argv']) ? $_SERVER['argv'] : array()),
        );
 
        /**
         * Aura\Cli\Context\Env
         */
        $di->params['Aura\Cli\Context\Env'] = array(
            'values' => $_ENV,
        );
 
        /**
         * Aura\Cli\Context\Server
         */
        $di->params['Aura\Cli\Context\Server'] = array(
            'values' => $_SERVER,
        );
 
        /**
         * Aura\Cli\Stdio
         */
        $di->params['Aura\Cli\Stdio'] = array(
            'stdin' => $di->lazyNew('Aura\Cli\Stdio\Handle', array(
                'name' => 'php://stdin',
                'mode' => 'r',
            )),
            'stdout' => $di->lazyNew('Aura\Cli\Stdio\Handle', array(
                'name' => 'php://stdout',
                'mode' => 'w+',
            )),
            'stderr' => $di->lazyNew('Aura\Cli\Stdio\Handle', array(
                'name' => 'php://stderr',
                'mode' => 'w+',
            )),
            'formatter' => $di->lazyNew('Aura\Cli\Stdio\Formatter'),
        );
    }
}

Now let’s rewind back to our script at the beginning:

exit((new ContainerBuilder())
    ->newInstance([], [Config::class])
    ->newInstance(Runner::class)
    ->run()
);

We already know that we created a container and plug services on it. The services are all that we have seen above. Things useful to turn prompt context into parameters and the name of the command to call, and things useful also to dispatch to that command, yes the dispatcher. And of course the command itself to which we now turn. So the instance of the DI container instantiates in turn the Runner class. This is our service defined in our namespace Cordoval\Console\Runner. Basically the specification of this for us is a service that will take in the Context service and the Dispatcher and uses these to gather the parameters and command name and dispatches to the callable that is the other command registered. The help command. We execute the run() method on the Runner as you can see:

<?php
 
namespace Cordoval\Console;
 
use Aura\Dispatcher\Dispatcher;
use Aura\Cli\Context;
 
/**
 * It loads cli context from prompt and dispatches to registered callable commands
 */
final class Runner
{
    private $dispatcher;
    private $context;
 
    public function __construct(Dispatcher $dispatcher, Context $context)
    {
        $this->dispatcher = $dispatcher;
        $this->context = $context;
    }
 
    public function run()
    {
        list($params, $command) = $this->loadContext();
 
        return (int) $this->dispatcher->__invoke($params, $command);
    }
 
    public function loadContext()
    {
        $params = $this->context->argv->get();
        array_shift($params);
        $command = array_shift($params);
 
        return [$params, $command];
    }
}

So this becomes very simple to read. Basically we load the context parameters and decipher the command name invoked, that is “`php console.php help“` will do invoke our help command.

        $di->params[Help::class] = [
            'context' => $di->lazyGet('cordoval:context'),
            'stdio' => $di->lazyGet('cordoval:stdio'),
        ];

Notice that we define our class as a parameter in the DI container and lazyload its 2 dependencies to be injected. That is the service period. The DI is amazingly versatile to do the heavy lifting for us. The second part in the modify() method is so to bind the callable Help::class to be invoked by name ‘help’:

        $di->get('cordoval:dispatcher')
            ->setObject('help', $di->lazyNew(Help::class))
        ;

It is wonderful now 🙂 Our command will be invoked whenever there is a dispatch on that name for that callable. Just picture command handlers here and you will start to grin.

Here is our command Help:class:

<?php
 
namespace Cordoval\Console\Task;
 
use Aura\Cli\Stdio;
use Aura\Cli\Context;
use Aura\Cli\Status;
 
class Help
{
    private $context;
    private $stdio;
 
    public function __construct(Context $context, Stdio $stdio)
    {
        $this->context = $context;
        $this->stdio = $stdio;
    }
 
    public function __invoke()
    {
        $this->stdio->outln('all good boss');
 
        return Status::USAGE;
    }
}

Dead simple, let it just be a callable. Is like an interactor, ready to be tested like one completely decoupled. The importance thing to see here is you are not relying on magical links between the console part (aka the Runner::class) and the command. The input/output stuff is encapsulated at the level that it should be. There is no messy confusion, all is crystal clear for you to adapt/modify. In fact, I did just that because AuraPHP already provides an example of Aura.Cli_Kernel and Aura.Cli_Project which tie some dependencies including a logger and other things minor. But in reality is that this is just for educational purposes for you to bootstrap quicker the project and understand better the internals of AuraPHP 2.0.

However, after seeing this there is no need if you understand the essence of this. You can do away with complexity and keep it simple. You can decouple your commands from any framework, the DI from AuraPHP is just a sauce on top of the real domain of your commands. Your code is free from strange interfaces other than the basic final-like classes such as Context, Stdio, and the ones you decide to keep injecting.

As a matter of fact, we are trying to rewrite GushPHP with libraries like this, because is much healthier for maintenance long term and inner quality. Symfony has its place but when it comes to decoupling AuraPHP 2.0 is superior. We still can use symfony components though I see no need really for now. Furthermore, you can now keep using tools like PhpSpec to concentrate on your classes, the collaborators of your commands, rather than concentrating on a TestCommand class or what not, or in functional tests which don’t make any sense when your commands can way much more benefit from a decoupled components first approach.

Enjoy and retweet please! Thanks!

Be Strict! PhpSpec 2 Best Practices Extension Just Released!

logo
image source: phpspec.net. Disclaimer: I have no affiliation with the creators of phpspec. I am just a user giving an opinion.

I just ran into a nice feature left out in the issues of phpspec and couldn’t resist to create my extension for it.

The trend is more and more generating final classes, this can be quickly achieved by a template under .phpspec folder. However, why do we want to copy paste templates all over the place? It makes little sense if in our projects we have determined to a strict adherence to better practices.

So I adapted my extension from the previous blog post and added a way to override completely with templates located on the extension itself.

<?php
 
namespace Cordoval\BestPractices\PhpSpec;
 
use PhpSpec\Extension\ExtensionInterface;
use PhpSpec\ServiceContainer;
 
class BestPracticesExtension implements ExtensionInterface
{
    /**
     * @param ServiceContainer $container
     */
    public function load(ServiceContainer $container)
    {
        $container->setShared('code_generator.generators.specification', function (ServiceContainer $c) {
            return new ClassNotationSpecificationGenerator(
                $c->get('console.io'),
                $c->get('code_generator.templates')
            );
        });
 
        $container->setParam('code_generator.templates.paths', array(
            rtrim(__DIR__, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'.phpspec',
        ));
    }
}

The way it is achieved is the following. PhpSpec has a way to override certain parameters. The template render mechanism first tries to use the renderer to get some content string rendered, if it is not found or the result is null then it moves into the default phpspec templates. So it first tries to check local project templates and under your home directory, and then it falls back to the phpspec package templates. To just lock the templates into our extension templates location we just override this parameter with our __DIR__/.phpspec location in our extension. Then just place the templates we want to override there and that is it.

We are very opinionated so here is the resultant package: cordoval/best-practice-extension

All you need is:

    // ...
    "cordoval/best-practice-extension": "~1.0@dev"
    "phpspec/phpspec": "~2.1@dev",
    // ...

Yeah, they don’t tag the package that often and we have templates moving after 2.0.1, sometimes we need help to follow best practices too :). So in any case with those requires you get it.

Then just add it to your phpspec.yml

extensions:
    - Cordoval\BestPractices\PhpSpec\BestPracticesExtension

And generate away! 🙂

PhpSpec ~2.0.1: Create your Extension like a Pro!

So I was motivated to tackle and create my own extension for PhpSpec but I did not know which use case I would be able to pull. I noticed quickly that the templates were a bit too simple so I extend my templates under .phpspec folder of my project to be something like:

// .phpspec/specification.tpl
 
    /**
     *
     */
    public function %name%(%arguments%)
    {
        return 0;
    }

First thing to notice is the idea with PhpSpec is that I will be testing behavior and expecting some kind of return value, be that an object or something boolean or such. So I rather just put the return since it will be there anyways. And because these methods are public i will also do a docblock and annotate the interface describing what it does. It sounds like what you want to do as good practice.

And this one below, take a look at this one because this one is taking advantage of the wonderful notation MyClass::class to provide the FQCN of the class in a short hand:

// .phpspec/specification.tpl
<?php
 
namespace %namespace%;
 
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use %subject%;
 
class %name% extends ObjectBehavior
{
    function let()
    {
        $this->beConstructedWith();
    }
 
    function it_is_initializable()
    {
        $this->shouldHaveType(%subject_name%::class);
    }
}

This is not the default template specification.template. there is a difference. I am using the short notation to place the subject class namespace without quotes into the argument of shouldHaveType. This will allow to keep the line very short and I am adding the use statement at the top.

It will just rock in action, you will see! 🙂

Now as I was going through the code of PhpSpec, I saw the setting up of generator services yey:

    /**
     * @param ServiceContainer $container
     */
    private function setupGenerators(ServiceContainer $container)
    {
        $container->setShared('code_generator', function (ServiceContainer $c) {
            $generator = new CodeGenerator\GeneratorManager();
 
            array_map(
                array($generator, 'registerGenerator'),
                $c->getByPrefix('code_generator.generators')
            );
 
            return $generator;
        });
 
        $container->set('code_generator.generators.specification', function (ServiceContainer $c) {
            return new CodeGenerator\Generator\SpecificationGenerator(
                $c->get('console.io'),
                $c->get('code_generator.templates')
            );
        });

So on my extension I could just replace this SpecificationGenerator that inside looks like:

namespace PhpSpec\CodeGenerator\Generator;
 
use PhpSpec\Locator\ResourceInterface;
 
/**
 * Generates spec classes from resources and puts them into the appropriate
 * folder using the appropriate template.
 */
class SpecificationGenerator extends PromptingGenerator
{
    // ...
 
    /**
     * @param ResourceInterface $resource
     * @param string            $filepath
     *
     * @return string
     */
    protected function renderTemplate(ResourceInterface $resource, $filepath)
    {
        $values = array(
            '%filepath%'  => $filepath,
            '%name%'      => $resource->getSpecName(),
            '%namespace%' => $resource->getSpecNamespace(),
            '%subject%'   => $resource->getSrcClassname()
        );
 
        if (!$content = $this->getTemplateRenderer()->render('specification', $values)) {
            $content = $this->getTemplateRenderer()->renderString($this->getTemplate(), $values);
        }
 
        return $content;
    }

Notice that this is the sucker that does the computation of the spec name and classnames and the same values for the source. But see that we are missing the name of the class getName() available in the resource. That we need to be able to just paste the name of the class and then the ::class invention.

What I did? well I created my extension class, and change that service:

<?php
 
namespace Cordoval\PhpSpec;
 
use PhpSpec\Extension\ExtensionInterface;
use PhpSpec\ServiceContainer;
 
class CordovalExtension implements ExtensionInterface
{
    /**
     * @param ServiceContainer $container
     */
    public function load(ServiceContainer $container)
    {
        $container->setShared('code_generator.generators.specification', function (ServiceContainer $c) {
            return new ClassNotationSpecificationGenerator(
                $c->get('console.io'),
                $c->get('code_generator.templates')
            );
        });
    }
}

And in my ClassnotationSpecificationGenerator I do:

$values = array(
            '%filepath%'  => $filepath,
            '%name%'      => $resource->getSpecName(),
            '%namespace%' => $resource->getSpecNamespace(),
            '%subject%'   => $resource->getSrcClassname(),
            '%subject_name%' => $resource->getName(),
        );

That is it, now my generated Specs look like:

<?php
 
namespace spec\Cordoval\Bus;
 
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Cordoval\Bus\CommandBus;
 
class CommandBusSpec extends ObjectBehavior
{
    function let()
    {
        $this->beConstructedWith();
    }
 
    function it_is_initializable()
    {
        $this->shouldHaveType(CommandBus::class);
    }
}

Which is to say a bit more interesting and keeps on saving you tons of time!

Visiting Phansible: Flint Web Ansible-based Vagrant Box Generator

Overnight I ran into this nice interesting project https://github.com/Phansible/phansible.
Don’t worry http://puphpet.com is not dead, at least not yet. Phansible still needs to support many more options before going mainstream. Users on puphpet side are many more so far and puphpet is being tested by many companies that have validated the generation. However Phansible is a very good promise built around ansible. And promises to get closer or even close the puphpet club in the future.

Phansible uses ansible recipe generation using twig and flint to generate from a webserver and some parameters or selections input into it a nice little zip file with your recipies and vagrant file. It generates playbooks, vagrantfiles, and varfiles.

You can just:

git clone git@github.com:Phansible/phansible.git
cd phansible
composer install
php vendor/bin/phpunit -c tests/phpunit.xml
php -S localhost:8080 -t web/

Though we are not very proud of the unit tests they exist and run fast. Though thoughts are being put together to improve that lacking side. Testing an app based on flint or pimple or such that inject the app into itself or such things is a bit weird as it is not inherently decoupled.

The project source code also contains a little gift which is the ansible folder. Yes the files used to deploy the same site :). This and how things get generated also for new projects will teach you a lot about ansible even if you don’t know anything about it.

When you want to generate things just go to the website or your local box deployed:

Screenshot 2014-09-10 05.40.23

vagrant up
 
// ...
 
 
PLAY [all] ********************************************************************
 
GATHERING FACTS ***************************************************************
ok: [192.168.33.99]
 
TASK: [init | Update apt] *****************************************************
ok: [192.168.33.99]
 
TASK: [init | Install System Packages] ****************************************
changed: [192.168.33.99] => (item=curl,wget,python-software-properties)
 
TASK: [init | Add ppa Repository] *********************************************
changed: [192.168.33.99]
 
TASK: [init | Update apt] *****************************************************
ok: [192.168.33.99]
 
TASK: [init | Install Extra Packages] *****************************************
changed: [192.168.33.99] => (item=vim,imagemagick)
 
TASK: [nginx | Install Nginx] *************************************************
changed: [192.168.33.99]
 
TASK: [nginx | Change default nginx site] *************************************
changed: [192.168.33.99]
 
TASK: [php5-fpm | Install php5-fpm and php5-cli] ******************************
changed: [192.168.33.99] => (item=php5-fpm,php5-cli)
 
TASK: [php5-fpm | Set permissions on socket - owner] **************************
changed: [192.168.33.99]
 
TASK: [php5-fpm | Set permissions on socket - group] **************************
changed: [192.168.33.99]
 
TASK: [php5-fpm | Set permissions on socket - mode] ***************************
changed: [192.168.33.99]
 
TASK: [phpcommon | Install PHP Packages] **************************************
failed: [192.168.33.99] => (item=php5-cli,php5-curl,php5-imagick,php-pear,php5-cgi,php5-common,php5-dbg,php5-enchant,php5-fpm,php5-gd,php5-geoip,php5-gmp,php5-imap,php5-interbase,php5-intl,php5-ldap,php5-mapscript,php5-mbstring,php5-mcrypt,php5-memcache,php5-memcached,php5-odbc,php5-pspell,php5-readline,php5-recode,php5-snmp,php5-sqlite,php5-svn,php5-sybase,php5-tidy,php5-xcache,php5-xdebug,php5-xmlrpc,php5-xsl) => {"failed": true, "item": "php5-cli,php5-curl,php5-imagick,php-pear,php5-cgi,php5-common,php5-dbg,php5-enchant,php5-fpm,php5-gd,php5-geoip,php5-gmp,php5-imap,php5-interbase,php5-intl,php5-ldap,php5-mapscript,php5-mbstring,php5-mcrypt,php5-memcache,php5-memcached,php5-odbc,php5-pspell,php5-readline,php5-recode,php5-snmp,php5-sqlite,php5-svn,php5-sybase,php5-tidy,php5-xcache,php5-xdebug,php5-xmlrpc,php5-xsl"}
msg: No package matching 'php5-mbstring' is available
 
FATAL: all hosts have already failed -- aborting
 
PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/cordoval/playbook.retry
 
192.168.33.99              : ok=12   changed=9    unreachable=0    failed=1
 
Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.

I got an error, but it is just probably because some updates were missing on the extensions.

There are some PRs about including frameworks however the best bet if you want to generate your own boxes and custom stuff is to clone and deploy privately a version of this. This way you can have your own recipies included. Though i strongly encourage you to share them with the rest of us!

Remember this is just the first stage of generation, you now can fix the generated files by hand, don’t forget to git init and ignore the .vagrant and other generated folders. After the fix just rerun the vagrant up or vagrant reload and then voila!

Personally I don’t use vagrant when I am a solo consultant but only when I work on a team environment. I am trying to improve a box generated by puphpet via phansible generated files now. Notice they will include Erika Heidi and other’s improvements so it is good to follow good practices from people that work with vagrant a lot more!

There are good practices also for writing ansible files here http://www.reinteractive.net/posts/167-ansible-real-life-good-practices

Encouragements and for now this is it, I will try to share more as I come more acquainted with phansible generation and testing boxes. Don’t forget to retweet please!