Posts Tagged programming coding php

Twig & Bery’s Update

One of the things I’ve been working lately on is a partial rewrite and refactoring of my wtBoard project (the engine behind SlackerTalk). The coding practices I used when I wrote it were somewhat undisciplined. As a result, it isn’t even loosely designed with MVC in mind; mostly, it uses old-school PHP practices like mixing PHP and HTML together inside functions. :evil: So, I have been incrementally fixing the code to be more organized and logical. One important part of that process has been Twig, the template engine featured by the Symfony2 framework.

Twig is a relative newcomer to the PHP templating rodeo, but it has several awesome features that make it the perfect choice for my refactoring plan – most importantly being that it isn’t tied to any other libraries or frameworks. You can run it independently and get access to its features.

  • Logic: Before I began working with frameworks, I tended to either mix HTML in with my code or roll my own templating solutions using str_replace(). I’ve even used in-house frameworks that implemented limited logic and control structures using PCRE. Instead, Twig’s robust set of logical operations, functions, and filters is great to work with, and it even implements things that PHP itself does not (such as an “else” option on “for/foreach” loops, for when the data set is empty).
  • Inheritance: Twig templates can inherit layout and other properties from parent templates, without requiring custom wiring in your code. This allows you to avoid code duplication in templates, and also lets you set up a custom templating environment.
  • Macros: Twig macros can be very useful for managing repeated blocks of logic in your templates, and combining them with inheritance allows you to accelerate template development.
  • Caching: When fully configured, Twig can “compile” its templates into raw PHP classes and store them in a cache – allowing them to be opcode-cached. While I haven’t benchmarked it, I’m sure it’s a bit faster than reading a file in and doing str_replace() in a huge loop for every page load.
  • Integration: You can easily add Twig to any existing PHP5.2.4 or higher code base. With a few lines of code, you’ll have access to logic, inheritance, macros, caching, extensions, and more – all achieved with a simple and flexible language definition.

Thanks to these benefits, I’ve been able to add Twig to my wtBoard project and begin the process of refactoring a jumble of raw-PHP-mixed-with-HTML into a svelte system of separated concerns.

That’s about the extend of hobby programming progress I’ve made over the past few months, so I guess I’ll do another programming post when I have something more interesting to talk about. Stay tuned for an update on my 2012 Photo-A-Day project, either this month or some time this quarter.

No Comments

PHP Annotations

Annotations are all the rage in some PHP circles these days, but I don’t like them. I try to avoid them as much as possible, and I hope that my reasoning for doing so is justified.

What are annotations?

Annotations are a form of meta-code; in practice, they allow you to modify attributes and behaviors of your methods and classes in fast and convenient ways. Three common uses for annotations in symfony2 are routing, validation, and ORM binding – although regular users of PHPUnit will also be familiar with annotations for data providers and test grouping.

Why are they awesome?

Annotations do have some good qualities. They allow you to reduce the clutter of your projects by folding various configuration and behavioural information into the class itself. For example, the average symfony2 bundle has a validation.yml and routing.yml file – both of these files can be eliminated or reduced in complexity by using annotations.

Additionally, annotations allow you to design and maintain your projects in a more straightforward manner. Instead of having to open one class file and a handful of configuration files (or a handful of supporting classes), all the information is right there within the primary class file.

You might be interested in this article on how to build custom PHP annotations, to see some of the power and flexibility they can bring to your projects.

Why am I avoiding them?

I must confess that I have a semi-irrational paranoia about using annotations. However, I feel that there are also some rational reasons to consider avoiding them.

One such reason is that the decentralization of certain types of configuration can lead to oversights and possible repetition of unanticipated mistakes, which can cause behavior that is unpredictable and hard to catch and debug. While the term “decentralization” might seem out of place when talking about merging code and configuration together, it helps to remember that a symfony2 bundle (or any PHP project) can have many controllers and classes and entities. You might end up with two controllers fighting over routing (an easy-to-solve issue, I’m sure), or you might find yourself struggling to remember a route name and which controller handles it (a situation where a single routing definition can help your code be more self-documenting).

There are also some speed concerns with annotations, due to the heavy use of Reflection, but they are mostly alleviated through the proper use of caching.

Most importantly, I feel that it is wrong to have what amounts to program logic tucked away in what otherwise looks like simple comments. If PHP had an official non-comment-like notation for annotations, I might be more inclined to use them. As it stands, I only use annotations in unit tests at the moment – not in the main/production code.

That’s pretty much the crux of what I don’t like about them: I do not like using comments as code.

How about you?

, , , ,

2 Comments

Quick Alerts in Silex

I’m currently working on a hobby project in Silex, and I ended up building a quick bit of code that might be helpful for people who like the “Flash Notice” functionality of Symfony2. This allows you to set some information in a session that displays on the next page load – such as after a redirect – and then vanishes on subsequent page loads.

This tip presumes that you are using the Twig and Session service providers in Silex.

Step 1: The Before Filter

First, we define a Before Filter. This is code that gets executed prior to any of your defined routes. Ours is going to inject a global variable into Twig.

/**
 * Before Filters
 */

$app->before( function() use ( $app ) {
    $flash = $app[ 'session' ]->get( 'flash' );
    $app[ 'session' ]->set( 'flash', null );

    if ( !empty( $flash ) )
    {
        $app[ 'twig' ]->addGlobal( 'flash', $flash );
    }
});

Step 2: The Twig Block

Now, we have to define how Twig will react to this flash notice. In this case, I have been using the Twitter Bootstrap CSS for prettying up my output, but you can style the alert any way you see fit.

{% block flash %}
{% if flash is defined %}
<div class="alert-message {{ flash.type }}">
<div class="container">
  <p><strong>{{ flash.short }}</strong> {{ flash.ext }}</p>
</div>
</div>
{% endif %}
{% endblock flash %}

Step 3: Setting the Flash

Of course, in order to use this, you need to set the flash array in the session.

$app[ 'session' ]->set( 'flash', array(
    'type'    =>'error', //other possible values include 'warning', 'info',
                        //'success' - it's part of Twitter Bootstrap
    'short'   =>'Permission Denied!',
    'ext'     =>'You must log in before you can access that resource.',
) );

//Redirect the user to another route
return new RedirectResponse( $app[ 'site_path' ] . 'login' );

And there you go! Symfony2-style flash notices … sort of … in Silex.

2 Comments

Using Silex for Console Tasks

Silex, the PHP Microframework based on Symfony2, is best-suited for rapid development of small web-based applications. But what if your web-based application needs to have scheduled tasks or other CLI-driven functionality? That’s where the Symfony2 Console Component comes into play.

In this blog post, I will go through the basic steps required to build a simple console task in Silex.

Ingredients

  • PHP (cli) 5.3 or newer
  • Silex: go to http://www.silex-project.org/ and download Silex.phar
    • As of this writing, the patch that enables this CLI compatability has not been made live [update: it's live now, use the above URL or php silex.phar update to get the latest version]. If you want to clone and compile Silex.phar on your own, see the footnotes :)
  • Console Component: The easiest way to obtain this is using “git”:
    • git clone git://github.com/symfony/Console.git

Pre-Heating the Oven

It’s helpful to structure your Silex project in a sane way, so to that end, I’d create a folder structure like this:

  • ProjectName
    • console.php
    • src/
      • silex.phar
      • bootstrap.php (more on this later)
    • vendor/
      • Symfony/
        • Component/
          • Console/ (Your cloned Git repository)

As you can see, even though we’re doing something the framework wasn’t specifically designed for, the requirements are very simple. Silex.phar vastly reduces the filesystem overhead for a project like this, to a point where only the “extras” need to be cluttering up your nice, clean project.

The Recipe

OK, here’s where I show you how it all fits together.

Step One is creating the bootstrap.php file. This allows you to extend Silex with external resources such as the Console component, or to build your own Silex extensions that allow code re-use between the console and the web-facing portions of your projects.

Example:

<?php

require_once __DIR__ . '/silex.phar';

$loader->register();

$app = new Silex\Application();
$app[ 'autoloader' ]->registerNamespace('Symfony', __DIR__ . '/../vendor');

return $app;

Step Two is building your ProjectName/console.php task script.

#!/usr/bin/env php
<?php

//Bootstrap our Silex application
$app = require __DIR__ . '/src/bootstrap.php';

//Include the namespaces of the components we plan to use
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

//Instantiate our Console application
$console = new Application('ProjectName', '0.1');

//Register a command to run from the command line
//Our command will be started with "./console.php sync"
$console->register( 'sync' )
  ->setDefinition( array(
     //Create a "--test" optional parameter
     new InputOption('test', '', InputOption::VALUE_NONE, 'Test mode'),
    ) )
  ->setDescription('Synchronize with an external data source')
  ->setHelp('Usage: <info>./console.php sync [--test]</info>')
  ->setCode(
    function(InputInterface $input, OutputInterface $output) use ($app)
    {
      if ($input->getOption('test'))
      {
        $output->write("\n\tTest Mode Enabled\n\n");
      }

      $output->write( "Contacting external data source ...\n");
      //Do work here
      //Example:
      //  $app[ 'myExtension' ]->doStuff();
    }
  );

$console->run();

Step Three is, as always, profit!

  • Mark the console script as executable:
    $> chmod u+x console.php 

The Goods

  • Show the help screen:

    $> ./console.php
    ProjectName version ProjectVersion
    
    Usage:
      [options] command [arguments]
    
    Options:
      --help           -h Display this help message.
      --quiet          -q Do not output any message.
      --verbose        -v Increase verbosity of messages.
      --version        -V Display this program version.
      --ansi              Force ANSI output.
      --no-ansi           Disable ANSI output.
      --no-interaction -n Do not ask any interactive question.
    
    Available commands:
      help   Displays help for a command
      list   Lists commands
      sync   Synchronize with an external data source
    
  • Show the help for our new command:
    $> ./console.php help sync
    Usage:
     sync [--test]
    
    Options:
     --test  Test mode
    
    Help:
     Usage: ./console.php sync [--test]
  • Run our command in test mode:
    $> ./console.php sync --test
    
    	Test Mode Enabled
    
    Contacting external data source ...
    
  • Run our command “for real”:
    $> ./console.php sync
    Contacting external data source ...
    

Footnotes

  • Compiling Silex
    • Step One: Update your php.ini to set “phar.read_only” to “Off”
    • Step Two: A Few Good Commands
      • $> git clone --recurse-submodules git://github.com/fabpot/Silex.git
        $> cd Silex
        $> ./compile
        
      • … and now you should have the newest possible silex.phar file :)
    • Step Three: Copy or symlink silex.phar to the location discussed above (Pre-Heating the Oven)
  • Adding more commands and arguments
  • Silex for the Web
    • At some point, I might post here about using Silex effectively for rapidly developing simple websites (a handful of dynamic pages to accomplish a simple goal) – this is the main reason for Silex’s existence. This post is more about augmenting the main purpose of Silex to better achieve the goal of effective microframework usage :)
  • Silex Extensions
    • The website for Silex contains documentation on how to create Extensions. This is the most intriguing feature of Silex for me: it should allow me to share code between contexts (web or console) for a simple web service, which means I only have to maintain one set of core functionality – and the only clutter in the entire project tree is almost purely dedicated to my own business logic. Additionally, if the project outgrows the limitations or philosophy of Silex (for example, if I start having to include a large number of components), it should be relatively easy to refactor the code into other frameworks – such as the core framework of Silex, Symfony2.

I’d like to thank @igorwesome and @fabpot for their help & examples while I was researching this post.

4 Comments