Source Maven

Code Partition for Beau Simensen

Symfony Live 2013 Portland: Embedded Composer

For the last few weeks I've been polishing Embedded Composer for my talk at Symfony Live 2013 in Portland.

Embedded Composer started its life as a part of Sculpin but was extracted so that other people could potentially use it. I'm hoping that Embedded Composer will help more people get interested in the idea of embedding Composer into their applications.

I'm super excited to have an opportunity to share this work with more people. I had a blast at Symfony Live 2012 in San Francisco. I'm hoping I can continue to attend these in the future.

I also took this opportunity to launch a new landing page for myself. beau.io is now live and showcasing this talk. :)

I'd love to get feedback on the talk. :) If you saw it in person, please rate my talk and provide some feedback. Otherwise, please send me a Tweet!

Composer is a wonderful way to manage a project. But what happens when you need your application to be extensible at runtime? Enter Embedded Composer. Embedding Composer will ensure that the dependencies already included by your application are taken into account when adding additional dependencies at runtime. While this can be very useful for any application that may be installed globally it is critical for any application that may be distributed as a phar.

Tags: symfony, composer, speaking, symfony_live

Sending a Pull Request on GitHub Even when the Base Repository You Want is Missing

You want to help out on a large project. You find a Pull Request that someone else is working on and decide you want to help out. You make your changes and are ready to send a Pull Request but to your surprise you find that the fork you want to send your PR to is not listed. What now?

It turns out this is a known limitation with GitHub's Pull Request implementation for network with many repositories. If there are too many forks GitHub filters the list to only include the most popular forks.

I've run into this a number of times, usually when trying to work with the php-fig/fig-standards repository. More often than not, if I want to send changes to someone else's proposal (a very common use case) I'll find that their repository is not listed in the "base repo" selection list:

base repo example

I've contacted GitHub about this several times. This most recent time I got antsy and started poking around while waiting for a response and came to a workaround on my own. Huzzah!

I received an email the next day stating that the team is "discussing ways to address this particular issue with large repository networks." It also included instructions on the same workaround. :)

The Workaround

It turns out it is pretty easy to get around this limitation with a little URL hacking. Using my example above as a reference, I can target a PR at any base repo I want using the following pattern and replacing base-repo-username and base-branch as needed:

https://github.com/simensen/fig-standards/pull/new/base-repo-username:base-branch...simensen:is-hit-is-miss

So if I want to send something to, say, tedivm's Cache proposal, I would use the following URL since the base-repo-username is tedivm and the base-branch would be Cache:

https://github.com/simensen/fig-standards/pull/new/tedivm:Cache...simensen:is-hit-is-miss

I've had mixed luck on what actually happens when loading the hacked URL. In at least one case either the "commits" or "files" tabs was missing content on viewing, despite having the correct number of items listed in the tabs. The PR worked just fine, though, so if you see this I don't think there is a lot of reason to be alarmed.

Hopefully GitHub will support this functionality natively sometime in the near future. Until then, this workaround should help people currently stuck on this problem.

Tags: github

Silex Service Providers and Controller Providers; What Is Safe To Do Where?

Since discussing writing Silex service providers a few edge cases have come up that I'd like to touch on. I've also learned more about controller providers and how they fit into the big picture. Here are a few more rules and guidelines to help make writing Silex service providers and controller providers a little easier.

Service Provider Registering Another Service Provider

One may be tempted to register another service provider from a service provider's register method. Take the following example:

use Silex\Application;
use Silex\Provider\DoctrineServiceProvider;
use Silex\ServiceProviderInterface;

public function MyServiceProvider implements ServiceProviderInterface
{
    public function boot(Application $app)
    {
    }

    public function register(Application $app)
    {
        // This is probably not wise.
        $app->register(new DoctrineServiceProvider);
    }
}

While there is nothing wrong with this from an interface perspective, it violates the spirit of the service provider contract.

One of the rules from Writing Silex Service Providers was to treat the Application type hint for register as if it were actually Pimple. Pimple does not have a register method so by this rule register should not be called from within register.

What about the fact that Pimple itself may some day support a register method of its own? Well, when that happens we can revisit the issue. :) Until then the existing rule holds.

But doesn't registering a service provider pretty much just defines more services? Yes, this is true. However, doing so hides the fact that the service provider is being registered from the user. This is not good.

Consider the example above where we are registering the Doctrine service provider. What happens if the user doesn't realize this and they register the Doctrine provider themselves? In some cases this may be mostly harmless but in others this could be very bad.

By registering another service provider directly we end up with two problems. First, we are hiding dependencies. Second, we are tying our service provider to a specific implementation.

Hidden Dependencies

Take a slightly extended example where Doctrine service provider is registered by a service provider:

use Silex\Application;
use Silex\Provider\DoctrineServiceProvider;
use Silex\ServiceProviderInterface;

public function MyServiceProvider implements ServiceProviderInterface
{
    public function boot(Application $app)
    {
    }

    public function register(Application $app)
    {
        // This is probably not wise.
        $app->register(new DoctrineServiceProvider);

        $app['myapp.someservice'] = $app->share(function () use ($app) {
            // do something with $app['db'];
        });
    }
}

Written this way our service provider has a hidden dependency on the Doctrine service provider.

Rather than register the Doctrine service provider directly we should document that the user needs to register it themselves. This allows them to register it and configure it however they see fit.

To quote Igor on why this is the best approach:

... it means you don't get to configure that provider when it is registered
it's about giving the user control and dependency inversion ...

Tied to a Specific Implementation

To take it a step further, we can document exactly what we need, namely that we need $app['db'] to be available and that it needs to be an instance of Doctrine DBAL Connection.

To help the user out we can say that this service can be provided by the Doctrine service provider and even use it in example code.

An example of this in action would be the requirements of the Doctrine ORM Service Provider:

Currently requires both dbs and dbs.event_manager services in order to work. These can be provided by a Doctrine Service Provider like the Silex or Cilex service providers. If you can or want to fake it, go for it. :)

As is usually the case, by not tying our service provider to another service provider directly we will also get the added benefit of increased testability for our service provider.

Responsibility of Controller Provider's connect() Method

The responsibility of a Controller Provider's connect method is to wire up controllers. That is it. The rule is simple. This means that services should not be defined in a controller provider.

A Single Class Can Provide Both Services and Controllers

When discussing controller services and splitting the service definitions from the routing, Igor reminded me of a simple truth about interfaces. Classes can implement more than one interface at a time.

This means that a class can implement both the service provider interface and the controller provider interface at the same time. This is a nice solution for building out a provider for controllers as services:

class MyAppControllersProvider implements
    ServiceProviderInterface,
    ControllerProviderInterface
{
    function boot(Application $app)
    {
    }

    function register(Application $app)
    {
        //
        // Define controller services
        //

        $app['myapp.hellocontroller'] = $app->share(function() use ($app) {
            return new MyApp\Controller\HelloController($app['some.service']);
        });
    }

    public function connect(Application $app)
    {
        $controllers = $app['controllers_factory'];

        //
        // Define routing referring to controller services
        //

        $controllers->get('/hello/{name}', 'myapp.hellocontroller:say')
            ->method('GET')
            ->bind('myapp.hello');

        return $controllers;
    }
}

This allows us to follow the rules of only defining services in register and only defining controllers in connect but keeping the code in the same class. Win!


One caveat to this is that we have to register and mount the provider separately. For example:

$myAppControllersProvider = new MyAppControllersProvider;

$app->register($myAppControllersProvider);
$app->mount('/', $myAppControllersProvider);

Mounting Controller Provider in boot()

It might seem logical to mount a controller provider in boot. While not strictly wrong since Application code is more or less safe to call from inside boot it is probably not the best choice.

Mounting a controller provider inside boot will take away some control of the controller provider from the user. For example, the user will lose the ability to mount the controller provider at a path of their choice.

So while one can do it, it would be best to do so sparingly. More often than not the right decision is probably to allow the user to mount the controller provider themselves.

Control

A common theme seen here is control. The question of mounting a controller in boot is similar to question of registering a service provider from within a service provider. Both are attempts to wrangle control from the user.

This control is important. We should do what we can to not limit it if we do not need to.

Join Us

Seriously, people, #silex-php rocks. Come join us if you want to discuss awesome things and learn Silex best practices. :)

Tags: silex

PHP-FIG Focus

I'm a huge fan of PHP-FIG. I take part where I think I can make a constructive contribution and I try to tune in to as many of the discussions as my time allows. So when I saw Larry's poll about the Focus of FIG I was happy to have the opportunity to share what I think PHP-FIG should be focusing on. This sparked an interesting conversation about whether I thought PSR-2 was a waste of time.


Larry specifically requested that people simply vote and not discuss the issue. I think this was a great idea and people have done a pretty good job of following this request. A downside to this is that people may wonder why someone votes the way they do when there is zero context for their vote.

Hari asked for more context from me on Twitter. I was happy to talk about it and I thought the discussion went well and was productive. However, I also found it hard to really express some of these complex ideas in 140 character bursts. So I told him I'd write about why I voted the way I did in more detail.


I was surprised that PHP-FIG got involved with PSR-2. I did not think that it was something that would further the groups goals. There were other interesting things happening at that point but the entire focus of the group turned to... a style guide? Really?

As far as I was concerned, the process for creating PSR-2 drew a lot of time and energy from places it could have been better spent. Since then PSR-2 has been a PR nightmare and a drain on resources.

This does not mean that I am not actively trying to write valid PSR-2 nor does it mean I don't see utility in having it available now that it already exist. Quite the opposite, in fact. How do I explain this duality?

First, it was done and it is now a thing. Why fight it?

Second, it was more or less compatible with Symfony CS. I had never had a formal CS for any of my projects in the past and I had recently decided to adopt Symfony CS for all of my projects. This is hugely important so it deserves some emphasis. Adopting PSR-2 for me meant changing nothing about the way I was already writing code.

Third, the notion of PSR-2 being an open and independent standard not tied directly to the Symfony framework meant that in theory I would be more likely to find other projects using my preferred personal/project CS. As someone who likes to promote writing framework agnostic code, this is a huge win!

So I can see how from the outside it would appear that I don't actually think that PSR-2 was a complete waste of time. Why did I vote 10, "Specs along the lines of PSR-3 that affect code-level interop. PSR-2-esque specs are a waste of time," instead of something a little softer?

PSR-2 exists now. There is nothing we can do about it. I actually find it to be useful and serving a purpose. That is a good thing! But this does not mean that I think PHP-FIG should spend resources on creating more specs like PSR-2.

For example, I think that proposals along the lines of SQL formatting standards* are just begging for trouble. Discussions like these are going to end up eating valuable resources and the end results will have a high probability of making even more people unhappy.

I would rather have PHP-FIG focus on bringing things like a Cache interface to the table than publishing something telling people how they should write a properly PSR formatted SQL query.

That said, I've learned over the last few years that some people think that interfaces may be a bad idea as well. So I guess you really can't make everyone happy. :)

In the end, I think that on average PHP-FIG will probably score somewhere in the middle. Some things will be more targeted at humans. Some will be more targeted at computers.

If I had a vote, though, I would vote that the group aim at computer related specs for awhile. I would vote for this in the hopes of getting some more wins in the group's column and hopefully avoid fresh human drama brought on by human oriented specs. Someday it may be safe to soften this stance, but for now I think this is the best way for PHP-FIG to move forward.

* I picked the SQL query example because it was the first thing that came to mind and I thought it made a great example of a human oriented spec. I realize the SQL PR was already closed at the time of writing. :)

Tags: php, php-fig, opinion, psr-2


Older Posts