Matthew 7:12: The DDD Project To Help (uses carefully some Symfony)

So we started Matthew 7:12. It is an open source project. It aims to solve the following situation:

In some countries, the internet is very controlled or minimum. The only way to contribute to an open source project is via email. I have heard that the linux kernel group also work using email and attaching patches. However I don’t think their approach solves this situation in a way that is acceptable for this other people.

Matthew is a server app that takes notices of new changes in a repository and email subscribed users patches attached to it. These patches are zipped and are split so no patch per email is larger than a threshold say 2 MB.

Matthew is also a server app that receives contributions, so not only sends them. Matthew is able to read an email account per project to check whether it has been emailed a patch. Each patch that Matthew reads is converted into a Pull Request to a given branch in a given repo.

The circle of contribution then is pushing code via email from contributors and creating PRs and notifying these users of new changes in the repo so that at any time all they would have to do is to send a patch of their changes or apply a patch received from upstream to continue developing.

Matthew will have options to bootstrap a repo on their locals, so easy download options considering split zips of the specific sections of a repository.

Matthew will use best practices and if you like those you already can tell from the repo here.

Is still under heavy construction and you are summoned to PR it, it is your responsibility how it ends up :)

We will deploy it soon too and test it!

Symfony CS Custom Fixer + Tests: Do focus on your goal!

Once again I received a closing ticket here https://github.com/fabpot/PHP-CS-Fixer/issues/381 in response to a feature request. There was no explanation why it was closed. However @stof kindly provided some reasoning. However what surprised me is what happened afterwards!

But it was great that @sstok picked it up and left a gist. This is amazing how the community can be so encouraging! Really thanks!

So I went and plugged this custom short syntax converter and here is the recipe!

<?php
 
namespace Decoupling\Fixer;
 
use Symfony\CS\FixerInterface;
use Symfony\CS\Tokens;
 
class ShortArraySyntaxFixer implements FixerInterface
{
    public function fix(\SplFileInfo $file, $content)
    {
        $tokens = Tokens::fromCode($content);
 
        for ($index = 0, $c = $tokens->count(); $index < $c; $index++) {
            $token = $tokens[$index];
 
            if (Tokens::isKeyword($token) && T_ARRAY === $token[0] && '(' === $tokens->getNextNonWhitespace($index)) {
                $this->fixArray($tokens, $index);
                continue;
            }
        }
 
        return $tokens->generateCode();
    }
 
    private function fixArray(Tokens $tokens, &$index)
    {
        $bracesLevel = 0;
 
        unset($tokens[$index]);
        $index++;
 
        for ($c = $tokens->count(); $index < $c; $index++) {
            $token = $tokens[$index];
 
            if ('(' === $token) {
                if (0 === $bracesLevel) {
                    $tokens[$index] = '[';
                }
 
                ++$bracesLevel;
                continue;
            }
 
            if (Tokens::isKeyword($token) && T_ARRAY === $token[0] && '(' === $tokens->getNextNonWhitespace($index)) {
                $this->fixArray($tokens, $index);
                continue;
            }
 
            if (')' === $token) {
                --$bracesLevel;
 
                if (0 === $bracesLevel) {
                    $tokens[$index] = ']';
                    break;
                }
            }
        }
    }
 
    public function getLevel()
    {
        return FixerInterface::ALL_LEVEL;
    }
 
    public function getPriority()
    {
        return 0;
    }
 
    public function supports(\SplFileInfo $file)
    {
        return 'php' === pathinfo($file->getFilename(), PATHINFO_EXTENSION);
    }
 
    public function getName()
    {
        return 'short_array_syntax';
    }
 
    public function getDescription()
    {
        return 'PHP array\'s should use the PHP 5.4 short-syntax';
    }
}

And its corresponding test:

<?php
 
namespace Decoupling\Tests\Fixer;
 
use Decoupling\Fixer\ShortArraySyntaxFixer;
 
class ShortArraySyntaxFixerTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider provideExamples
     */
    public function testFix($expected, $input)
    {
        $fixer = new ShortArraySyntaxFixer();
        $file = $this->getTestFile();
 
        $this->assertEquals($expected, $fixer->fix($file, $input));
    }
 
    public function provideExamples()
    {
        return [
            ['<?php $x = [];', '<?php $x = array();'],
            ['<?php $x = []; $y = [];', '<?php $x = array(); $y = array();'],
            ['<?php $x = [ ];', '<?php $x = array( );'],
            ['<?php $x = [\'foo\'];', '<?php $x = array(\'foo\');'],
            ['<?php $x = [ \'foo\' ];', '<?php $x = array( \'foo\' );'],
            ['<?php $x = [($y ? true : false)];', '<?php $x = array(($y ? true : false));'],
            ['<?php $x = [($y ? [true] : [false])];', '<?php $x = array(($y ? array(true) : array(false)));'],//
            ['<?php $x = [($y ? [true] : [ false ])];', '<?php $x = array(($y ? array(true) : array( false )));'],
            ['<?php $x = [($y ? ["t" => true] : ["f" => false])];', '<?php $x = array(($y ? array("t" => true) : array("f" => false)));'],
            ['<?php print_r([($y ? true : false)]);', '<?php print_r(array(($y ? true : false)));'],
            ['<?php $x = [[[]]];', '<?php $x = array(array(array()));'],
            ['<?php $x = [[[]]]; $y = [[[]]];', '<?php $x = array(array(array())); $y = array(array(array()));'],
        ];
    }
 
    private function getTestFile($filename = __FILE__)
    {
        static $files = [];
 
        if (!isset($files[$filename])) {
            $files[$filename] = new \SplFileInfo($filename);
        }
 
        return $files[$filename];
    }
}

This is also in a gist @sstok posted, however i have applied the fixer on the code itself :) and also fixed missing namespaces and opening php tags.

Your typical .php_cs then becomes:

<?php
 
require_once __DIR__.'/src/Decoupling/Fixer/ShortArraySyntaxFixer.php';
 
$finder = Symfony\CS\Finder\DefaultFinder::create()
    ->notName('README.md')
    ->notName('.php_cs')
    ->notName('composer.*')
    ->notName('phpunit.xml*')
    ->notName('*.xml')
    ->exclude('app')
    ->exclude('bin')
    ->exclude('migrations')
    ->exclude('vendor')
    ->exclude('web/bundles')
    ->in(__DIR__)
;
 
return Symfony\CS\Config\Config::create()
    ->addCustomFixer(new Decoupling\Fixer\ShortArraySyntaxFixer)
    ->fixers(
        [
            'encoding',
            'linefeed',
            'indentation',
            'trailing_spaces',
            'object_operator',
            'phpdoc_params',
            'visibility',
            'short_tag',
            'php_closing_tag',
            'return',
            'extra_empty_lines',
            'braces',
            'lowercase_constants',
            'lowercase_keywords',
            'include',
            'function_declaration',
            'controls_spaces',
            'spaces_cast',
            'psr0',
            'elseif',
            'eof_ending',
            'one_class_per_file',
            'unused_use',
            'short_array_syntax',
        ]
    )
    ->finder($finder)
;

Now go and run it:

~ php-cs-fixer fix .

It worked like a charm in my project and I am happy to use it even in gush now, PR coming!

joyfully undeservedly ending this post!

your friend @cordoval

Security Check For Symfony Component-Based Projects

Misunderstandings and clashes of cultures and worrying may end up in good. It maybe hard to see the outcome but in the end with some favor this is good.

On June 17, 2014 I received this surprising message from @fabpot, the symfony lead maintainer, I was very sad to see this in such a way. It really saddened me for a bit, and made me think about my commenting a bit, then I went back and recalled and really was acting in my best for asking the right questions. Yet for some reason culturally, maybe having a bad day or other reason, I got discouraged in such a way.

Then I thought why not jumping and continuing in the idea so to really get an answer rather than just stay crying because someone did not like your question. Then I took on the challenge!

So I went and saw a commit from @fabpot himself adding it to the security-checker repo then I sent a PR to my own fork https://github.com/cordoval/security-checker/pull/1/files enabling the checker to become finally a phar for everybody to generate.

After this I went and prepared a script on Gush to test this approach, created a release of the phar on github and created a script to download it and run it and plugged it into the bldr.io bldr.yml file in the Gush project:

// ./secure
#!/usr/bin/env bash

securitychecker=$(which security-checker)
 
if [ -x "$securitychecker" ] ; then
    $securitychecker security:check
else
    if [ ! -f ./security-checker.phar ]; then
        wget https://github.com/cordoval/security-checker/releases/download/v1.3.1/security-checker.phar
    fi
 
    chmod +x ./security-checker.phar
    ./security-checker.phar security:check
fi

and task added to bldr.yml:

+        secure:
 +            calls:
 +                -
 +                    type: exec
 +                    failOnError: true
 +                    executable: ./secure
 +                    arguments: []

Then we get travis-ci happy about our security:

Screenshot 2014-06-18 23.10.00

I like @fabpot but no matter who is telling you to stop, if it is a good thing and you are asking questions my advise is to keep working on them.

Encouragements!