Symfony2 Parameters Updater Script

Recently our very own @Stof open sourced a script handler for composer so that it would basically prompt you on the console and ask you to set values to new parameters updated on the app/config/parameters.yml.dist but that you did not have on app/config/parameters.yml yet because you just were unaware of.

This problematic happens on team work. When a team is working on a repository we often create new parameters to be used by the application on parameters.yml or modify their values or their names, then commit the change and push. If our teammates are unaware of this change, next time they will pull the changes on the master or development branch then the system will give an error saying we miss such and such parameter. The script handler was born to cope with these types of situations.

I would in fact assume after you pull new changes on a main branch you either dutifully run composer install or composer update if it is your job, or you have a hook that runs this for you automatically after pull ;).

In any case because this script handler package is new and needs quick adoption to take advantage of this util, I wrote a script that would update your composer.json and will save you the time to update your old composer.json files. If you are handling many projects like @Stof or @lsmith then you would probably use something like this and run it for many projects recursively.

To run the script just cd into your project directory and issue the following command:

~ curl -L http://bit.ly/RVv0yr | php

That is it! The command adds the right lines to add to fetch and configure Stof’s package so you don’t spend time configuring it.

If you want to know the inner parts of the script here it is:

<?php
 
/**
 * @author: Luis Cordova <cordoval@gmail.com>
 *
 *     Thanks Lord for enjoying my work and all of this undeservingly.
 *
 */
 
$c = json_decode(file_get_contents('composer.json'), true);
 
if (!isset($c['scripts']['post-install-cmd'])) {
  $c['scripts']['post-install-cmd'] = array();
}
 
if (!in_array("LogSafe\\ParameterHandler\\ScriptHandler::buildParameters", $c['scripts']['post-install-cmd'])) {
    array_unshift($c['scripts']['post-install-cmd'], "LogSafe\\ParameterHandler\\ScriptHandler::buildParameters");
}
 
if (!isset($c['scripts']['post-update-cmd'])) {
  $c['scripts']['post-install-cmd'] = array();
}
 
if (!in_array("LogSafe\\ParameterHandler\\ScriptHandler::buildParameters", $c['scripts']['post-update-cmd'])) {
    array_unshift($c['scripts']['post-update-cmd'], "LogSafe\\ParameterHandler\\ScriptHandler::buildParameters");
}
 
$c['require']['logsafe/composer-parameter-handler'] = "*";
$c['extra']['logsafe-parameters']['file'] = "app/config/parameters.yml";
 
file_put_contents('composer.json', encode($c));
 
 
// follows function taken from composer
 
    /**
     * I took this from composer's codebase. The function encode is not my own.
     * Please refer to:
     *     https://github.com/composer/composer/blob/master/src/Composer/Json/JsonFile.php#L160
     *
     * Encodes an array into (optionally pretty-printed) JSON
     *
     * This code is based on the function found at:
     *  http://recursive-design.com/blog/2008/03/11/format-json-with-php/
     *
     * Originally licensed under MIT by Dave Perrett <mail@recursive-design.com>
     *
     * @param  mixed  $data    Data to encode into a formatted JSON string
     * @param  int    $options json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
     * @return string Encoded json
     */
    function encode($data, $options = 448)
    {
        if (version_compare(PHP_VERSION, '5.4', '>=')) {
            return json_encode($data, $options);
        }
 
        $json = json_encode($data);
 
        $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
        $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
        $unescapeSlashes = (bool) ($options & self::JSON_UNESCAPED_SLASHES);
 
        if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
            return $json;
        }
 
        $result = '';
        $pos = 0;
        $strLen = strlen($json);
        $indentStr = '    ';
        $newLine = "\n";
        $outOfQuotes = true;
        $buffer = '';
        $noescape = true;
 
        for ($i = 0; $i <= $strLen; $i++) {
            // Grab the next character in the string
            $char = substr($json, $i, 1);
 
            // Are we inside a quoted string?
            if ('"' === $char && $noescape) {
                $outOfQuotes = !$outOfQuotes;
            }
 
            if (!$outOfQuotes) {
                $buffer .= $char;
                $noescape = '\\' === $char ? !$noescape : true;
                continue;
            } elseif ('' !== $buffer) {
                if ($unescapeSlashes) {
                    $buffer = str_replace('\\/', '/', $buffer);
                }
 
                if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
                    // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha
                    $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match) {
                        return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
                    }, $buffer);
                }
 
                $result .= $buffer.$char;
                $buffer = '';
                continue;
            }
 
            if (':' === $char) {
                // Add a space after the : character
                $char .= ' ';
            } elseif (('}' === $char || ']' === $char)) {
                $pos--;
                $prevChar = substr($json, $i - 1, 1);
 
                if ('{' !== $prevChar && '[' !== $prevChar) {
                    // If this character is the end of an element,
                    // output a new line and indent the next line
                    $result .= $newLine;
                    for ($j = 0; $j < $pos; $j++) {
                        $result .= $indentStr;
                    }
                } else {
                    // Collapse empty {} and []
                    $result = rtrim($result)."\n\n".$indentStr;
                }
            }
 
            $result .= $char;
 
            // If the last character was the beginning of an element,
            // output a new line and indent the next line
            if (',' === $char || '{' === $char || '[' === $char) {
                $result .= $newLine;
 
                if ('{' === $char || '[' === $char) {
                    $pos++;
                }
 
                for ($j = 0; $j < $pos; $j++) {
                    $result .= $indentStr;
                }
            }
        }
 
        return $result;
    }

@Stof stoffed it a bit and pointed me to the composer function encode and I was able to finish it and write this blog post you are enjoying. You can send your encouragements to me here thanks! And from now on we should not hear excuses like: `You did not tell me about this new parameter and I spent hours on this!`.

Encouragements in all good!

Leave a Reply

Your email address will not be published. Required fields are marked *