Symfony 2.7: LTS is the feature

Three years of bug fixes. Four years of security fixes. Symfony 2.7 came out this weekend, and that is the line from the announcement I care about. The changelog has new things in it, but the important word is on the label: LTS. For a pet project this is boring. For a product with paying users and a team, this is the actual feature. A big application does not upgrade for fun. Every framework upgrade is testing time, regression risk, and a sprint that produces nothing visible. Business asks a fair question: what do we get. “Newer version” is not an answer. “We keep receiving security fixes until 2018 without touching anything” is. ...

May 31, 2015 · 2 min · Murat Useinov

Where Doctrine spends your milliseconds

$order->getCustomer()->getName() inside a foreach. Every time I open a slow Doctrine endpoint, I find some version of this line within ten minutes. The PHP is rarely slow. The shape of the data access is. Same few places every time. Lazy loading. The classic N+1. Doctrine proxies make it invisible: you touch the relation in a loop and every touch is a query. The profiler query count tells the truth. The code does not. ...

April 23, 2015 · 2 min · Murat Useinov

Three ways to get a dependency in Laravel

Same repository, three ways to get it in Laravel 5. // 1. Constructor injection public function __construct(OrderRepository $orders) { $this->orders = $orders; } // 2. Facade $order = Orders::find($id); // 3. Service locator $orders = App::make('App\Repositories\OrderRepository'); All three work. The container resolves everything either way. The difference is in what the class tells you about itself. With constructor injection the dependencies are in the signature. You open the class, you read the constructor, you know what it needs. A test passes a mock and never touches the container. ...

March 9, 2015 · 2 min · Murat Useinov

Laravel 5 and the death of the models folder

app/models is gone. Laravel 5 came out at the start of the month, and of everything in the release the folder I notice most is the one that no longer exists. The old skeleton had app/models and app/controllers. You knew where things go because the framework told you. Laravel 5 removes that. There is app/, it maps to the App namespace through PSR-4, and inside it you organize classes however you want. ...

February 25, 2015 · 2 min · Murat Useinov

Composer in a legacy Kohana project

require APPPATH.'../vendor/autoload.php'; One line in bootstrap.php. This month it became the whole strategy for a project we decided to keep on Kohana. The framework is quiet, the project is alive. These two facts have to coexist somehow. The plan: nothing new gets written the Kohana way. New dependencies come through Composer, and Kohana’s autoloader and Composer’s autoloader live together fine. First candidate was the HTTP client. We talk to two external APIs, and the code around Request_Client_External was not pretty. Guzzle is better in every way. But Guzzle does not spread through the codebase. There is an interface: ...

January 22, 2015 · 2 min · Murat Useinov

Host header is user input

$link = 'https://'.$_SERVER['HTTP_HOST'].'/reset/'.$token; I wrote this line. More than once. It builds the link for a password reset email, and it looks like it reads something about the server. It does not. Host comes from the client, same as any other header. Kohana 3.3.4 shipped this month with a fix around exactly this, and the topic is bigger than one framework. The attack is short. Someone requests a password reset for your email address and puts his own domain into the Host header. The application trusts the header, builds the link, sends it. You receive a real email from a real site with a link to evil.example and your real token in the path. You click. He collects the token. Host header poisoning, and no framework protects you from it out of the box. ...

December 23, 2014 · 2 min · Murat Useinov

Symfony 2.6: dump() and boring upgrades

dump() instead of var_dump(). Symfony 2.6 came out at the end of November, and this is the visible gift: VarDumper. Collapsible output, clickable class names, works inside the toolbar. A small thing, used fifty times a day. Tools like this improve life more than big features do. But the important story in 2.6 is not a feature. The release notes read like a preparation checklist for Symfony 3: deprecations, everywhere. ...

December 18, 2014 · 2 min · Murat Useinov

Symfony best practices: defaults, not laws

One AppBundle. That is the line in the official Symfony Best Practices book I read twice. For years the answer to “how many bundles” was “as many as you have features”, and here the framework’s own book says: one. The book came out this autumn. Worth reading even if you are not on Symfony, because the interesting part is the change of tone. The old Symfony way: everything is a bundle. Your application is bundles, reusable, configurable, with their own extensions and semantic configuration. Very flexible. And for a normal business application, mostly ceremony. You write a configuration class for code that will never leave this one project. I wrote such classes. Three of them. None was ever reused. ...

December 14, 2014 · 2 min · Murat Useinov

Debug toolbar in production is a gift to strangers

/_profiler on a live site. Type it after any Symfony domain and sometimes it answers. This autumn the story went around, and I will not retell it. The lesson is bigger than one framework. Think what a profiler actually stores. Every SQL query with parameters. Cookies and session data. Routes, controller names, request headers. Sometimes config values. A full X-ray of your application, nicely formatted, with search. Now count how many sites have /_profiler or a debugbar open to the world because someone deployed with app_dev.php, or left debug = true in the production config. Not a rare exotic mistake. I saw it. I made it once, on a staging server that stayed reachable from outside longer than anyone planned. ...

December 9, 2014 · 2 min · Murat Useinov

PHP 5.6: small syntax, big TLS surprise

A nightly cron failed silently for two days. That was our PHP 5.6 upgrade. 5.6 is out since the end of August, and we moved one production project this month. The syntax part is pleasant and minor. Variadics: function log_all($level, ...$messages) { } Argument unpacking with ...$args on the call side. Constant expressions in defaults. use function for importing functions. All nice. None of it changes your architecture. You will use variadics maybe twice a year and be happy both times. ...

December 5, 2014 · 2 min · Murat Useinov