Sell me on your framework

I’ve got a major project upcoming and it is beyond the capacity of my own framework to scale to within a reasonable time frame. So pitch me your favorite framework. The leading contenders in my mind at this point are ZF2, Cake and CodeIgniter. Here are the requirements.

  • PHP 5.4 compatible, preferably able to allow traits to be deployed.
  • Must have unit testing ability, preferably with PHP Unit.
  • Must not have configuration files so god-awful complex they constitute their own programming language.

I used the Zend Framework once, and now I can’t move for beautiful women.

I of course know Symfony best, so that’s what I describe below. It would certainly be interesting if others make similar posts in their respective framework. I’m interrested to see them all side by side. (@K_Wolfe ;?)

I’m not sure which details you’re most interested in, so I’ll try to give an abbreviated summary of workflow in Symfony.

– Routes –

Routes can be defined with plain PHP, Yaml, XML, or annotations. Here’s a quick example of each (except XML, 'cause… bleh).

# plain PHP
        $routeCollection->add('article_show', new Route('/articles/{slug}', array(
            '_controller' => 'YourProjectBundle:Article:show',
        )));
# Yaml
        article_show:
            path:     /articles/{slug}
            defaults: { _controller: YourProjectBundle:Article:show }
# Annotation
        /**
         * @Route("/articles/{slug}")
         */
        public function showAction()
        {
            // ...
        }

– Controllers –

In Symfony, a controller is any callable that accepts a request and returns a response.

    public function showAction(Request $request)
    {
        // ...

        return new Response();
    }

Symfony provides a few convenience shortcuts. A controller’s arguments can be the route parameters, and a render method can render a template and compose the response.

    public function showAction($slug)
    {
        // ...

        return $this->render('YourProjectBundle:Article:show.html.twig', array(
            'article' => $article
        ));
    }

– Templates –

Templates in Symfony typically define blocks. They then “extend” another template that uses those blocks.

# show.html.twig
        {% extends 'YourProjectBundle::layout.html.twig' %}

        {% block title %}
            {{ article.title }}
        {% endblock %}

        {% block body %}
            <h2>{{ article.title }}</h2>
            <p>{{ article.body }}</p>

            <!-- output escaping happens automatically and by default
                 no xss vulnerabilities here -->
        {% endblock %}
# layout.html.twig
        <!DOCTYPE html>
        <html>
            <head>
                <title>{% block title %}Default Title{% endblock %}</title>
            </head>
            <body>
                <div id="sidebar">
                    <ul>
                        <li><a href="/">Home</a></li>
                        <li><a href="/blog">Blog</a></li>
                    </ul>
                </div>

                <div id="content">
                    {% block body %}{% endblock %}
                </div>
            </body>
        </html>

Templates can also “include” other template snippets, or they can “render” (embed) the output from other controllers.

You also have the option to use plain PHP temlates if you choose.

Symfony also comes packaged with the Assetic library. JS and CSS can be automatically combined and minified in prod, and in dev they can be served separate and un-unminifed. Assetic can also compile SASS, LESS, and several others for you.

– Model –

Models in Symfony are separate from the persistence mechanism (such as a database). A model is made up of very simple classes.

    class Article
    {
        private $title;

        private $body;
    }

How the entity classes behave and interact with each other is what defines your business logic.

To persist your entities (aka, save to database), Symfony comes packaged with the Doctrine ORM. (You also have the option of using Propel, or any other ORM, or no ORM). There are several ways you can tell Doctrine how to persist your entities.

# plain PHP
        $metadata->mapField(array(
           'fieldName' => 'title',
           'columnName' => 'title', // optional if field and column names are the same
           'type' => 'string'
        ));
# Yaml
        Article:
            type: entity
            fields:
                name: title
                column: title
                type: string
# Annotation
        class Article
        {
            /**
             * @ORM\\Column(name="title", type="string")
             */
            private $title;

            // ...
        }

Then Doctrine can save and retrieve Article objects, and generate your schema.

– Testing –

Symfony isn’t tied to any particular testing framework, though the documentation examples do indeed use PHPUnit.

The Symfony profiler is also pretty stellar.

(More to come perhaps late tomorrow. Forms, validation, caching, security…)

Please for the sake of of the OOP gods don’t consider using annotations for configuring objects.

Can you elaborate on that more? I would assume that is because it has to be read during run time causing a lot of I/O versus running a tool before deployment that may generate the YAML from the annotations?

I’ve written about it in detail here: http://r.je/php-annotations-are-an-abomination.html but a brief overview is:

  1. They break version control. If you want two differently configured instances of an object in different projects they become different branches even though it’s the configuration that’s changed and not the logic. This means you can’t fix a bug in one project and easily deploy the code to another project because the configurations may be different.

  2. They reduce portability. If you move a class around between two projects that use annotations, the annotations may break the second project

  3. They break encapsulation. The application code shouldn’t be concerned with how it will be used externally. Annotations tell the client code what it should be doing. Rather than letting the client code decide, in Jeff’s @Route example, the supplier code (the one with the annotation) is dictating how the outside world handles it. This is a direct violation of encapsulation because the object in question has direct knowledge and control over how external clients will use it. In OOP a class should be entirely self contained, exposing only a minimal number of methods which enable clients to interact with it. The object itself should not know anything about the nature of the clients that are going to use it, annotations assume knowledge about such clients.

  4. They limit flexibility. Using Symfony’s @Inject as an example, it’s impossible to create two instances of the class with different injected parameters because the dependency is defined at a class level, not an object level.

:slight_smile: That’s a very good summary. Living on the API side of the world I don’t get to work in a lot of Frameworks as they are designed with refactoring in mind and in many ways an API isn’t. You have to support your old versions, along with new ones, so you have a lot of duplication going from version 1 and 2 especially if you plan to keep supporting version 1 along side of version 2 (very true in situations where v2 contains many breaking changes). So it is nice to see some of the “other side” of things (I wish I were on that side occasionally).

Albeit there are ways of using frameworks with APIs, they just aren’t the “norm” (granted I’m sure as I continue to learn more, my approach may shift to support it better through frameworks).

Also when v2 includes many breaking changes, your version control usually denotes a specified branch/fork for v2 to keep it separate from v1 that has its own branch tree as well for features, bugs, releases, etc. So all of the limitations that annotations provide wouldn’t impact an API development routine as much as it would in other areas.

Inspired by: @Jeff Mott’s post on Symfony

My favourite framework is the robust CodeIgniter, since it not only does everything it says on the tin but also alleviates the drudgery of re-inventing the wheel.
Excellent documentation with accompanying source code makes adding new features pleasurable.

Since it is relatively easy to install I created a brand new application and added a few menu items complete with content details.

If you are interested then the project can be seen online with instructions and downloadable zipped source files.

The project details how a simple menu can be used to load various content files. Once installed content files may be added, modified or overwritten with your own content.

  1. Installing to a sub-directory is recommended:
  2. can be easily configured to use your online databases
  3. does not interfere with your existing project
  4. benchmarking is simple and detailed
  5. experiment with numerous caching types
  6. compare the Active Record Class SQL statements with your own!

Database setup requires a minimum of the four usual parameters (username, password, database name, etc.) and once set either your own SQL statements can be used or the “Active Record Class”. The latter is a wonderful database feature which simplifies writing SQL statements but especially since all statements are interpretated depending on the selected database driver type: mysql, mysqli, postgre, odbc, mssql, sqlite or oci8.

No doubt you shudder when having to change an existing project, all that is required is to use the Active Record Class and switch drivers. Magic.

Calories Setup, installation details and downloads

@Michael_Morris; - I look forward to seeing if the framework meets your requirements:
PHP 5.4 compatible, preferably able to allow traits to be deployed.
Must have unit testing ability, preferably with PHP Unit.
Must not have configuration files so god-awful complex they constitute their own programming language.