Whitewashing is the blog of Benjamin Eberlei and covers topics in software-development and object-oriented-design. Benjamin works for Qafoo and you can book him for consulting and trainings.
With the Windows Azure Websites platform-as-a-service (PaaS), which was released as a preview to a general audiance in June last year, PHP applications can be deployed to Azure with as much as a Git push to a remote repository. At the same time Microsoft released a new and much improved PHP SDK, which integrates with all the Azure webservices.
I blogged about deployment with Composer on Azure Websites last November and since then I have been working with Microsoft to improve Symfony2 support on Windows Azure by developing and releasing the AzureDistributionBundle. This is a new version of the bundle and contains the following improvements:
You can install both the Bundle or the Demo application via Composer. For the Demo application call:
$ php composer.phar create-project beberlei/symfony-azure-edition
The README includes more information about how to deploy the demo to your Azure websites account.
The bundle can be installed using the following composer.json:
{
"require": {
"beberlei/azure-distribution-bundle": "*"
},
"repositories": [
{
"type": "pear",
"url": "http://pear.php.net"
}
],
}
Registering PEAR is necessary, because the Azure PHP SDK depends on some PEAR components.
In a Twitter discussion yesterday I formulated my negative opinion about traits and Matthew asked me to clarify it:
I used to look forward to traits as a feature in PHP 5.4, but after discussions with Kore I came to the conclusion that traits are nothing else than static access in disguise. They actually lead to the exact same code smells. Familiar with the outcome of too much static use, we should reject traits as just another way of statically coupling your code to other classes.
Let’s step back and take a look at the code smells that Static code produces:
This blog post shows that Traits actually have the first three problems themselves and exhibit the same code smells. But they even have some additional problems on their own:
Take the following code, which tries to implement reusable controller code through traits:
<?php
class MyController
{
use Redirector;
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function someAction()
{
return $this->redirect("route_xyz", array());
}
}
trait Redirector
{
public function redirect($routeName, $parameters)
{
return new RedirectResponse(
$this->generateUrl($routeName, $parameters)
);
}
public function generateUrl($routeName, $parameters)
{
return $this->container->get('router')->generateUrl(
$routeName,
$parameters
);
}
}
Lets spot the problems:
Redirector is tightly coupled to MyController. There is no way to change this during runtime, by using a different type of redirector, it has to be exactly the trait used at compile time. This is exactly what static access enforces as well.
The trait accesses $this->container without defining it and couples itself against the implementing classes. We can actually refactor this to include an abstract method getContainer() in the trait. But if we have multiple traits now, all having a getContainer() method then we run into method class problems that cannot be solved. We could pass the container as an argument to the method, but that actually defeats the purpose of the abstraction here.
Traits using state of their “parents” usually create bidirectional coupling between classes, something which should be avoided for good software design.
No way to overwrite subset of functionality. If I want to use only one method of a trait and a second one slighty different, then I cannot overwrite this function of Redirector for example in MyController.
I cannot mock the traits functionality, therefore I cannot test MyController as a unit only in combination with a trait.
I cannot test the trait as a unit, I always have to create a class that uses the trait to be able to write a test for it. This prevents me from testing traits in isolation.
Once you start using Redirector in many controllers, its impact on your code base (see Code Rank) increases a lot. Traits are concrete implementations and therefore violate the Dependency Inversion SOLID principle: Changes in the trait require adoptions in all the implementing classes.
With aggregation you could depend on an abstraction Redirector or turn it into an abstraction in the moment that you need different functionality.
The discovery of this properties of traits me to the conclusion that traits are just static access in disguise.
To see this argument a bit more drastically, you can “rewrite” a PHP 5.4 trait into “pseudo” static code:
<?php
class MyController
{
public $container;
public function __construct($container)
{
$this->container = $container;
}
public function someAction()
{
return Redirector::redirect("route_xyz", array());
}
}
class Redirector
{
public function redirect($routeName, $parameters)
{
return new RedirectResponse(
self::generateUrl($routeName, $parameters)
);
}
public function generateUrl($routeName, $parameters)
{
return $this->container->get('router')->generateUrl(
$routeName,
$parameters
);
}
}
Calling dynamic methods statically actually works right now (and access to $this of the parent class will luckily be removed in PHP 5.5). Let’s reformulate it into something that is actually using static methods and will work on 5.5, requires changes to the visibility of properties though:
<?php
class MyController
{
public $container;
public function __construct($container)
{
$this->container = $container;
}
public function someAction()
{
return Redirector::redirect($this, "route_xyz", array());
}
}
class Redirector
{
public static function redirect($thiz, $routeName, $parameters)
{
return new RedirectResponse(
self::generateUrl($thiz, $routeName, $parameters)
);
}
public static function generateUrl($thiz, $routeName, $parameters)
{
return $thiz->container->get('router')->generateUrl(
$routeName,
$parameters
);
}
}
Can you see the familiarity? If Traits can be rewritten as calls to static methods, how can they be any better than static methods? They exhibit the exact same problems and produce the same code smells.
Conclusion: Traits should be avoided at all costs, just like static methods.
Rule of Thumb: If you want to use a trait, try to think how to solve the problem with aggregation.
If you want to read more about problems with traits, Anthony wrote about them quite a while ago.
Side projects have always been an important part of how I learn new skills and technologies. This usually ends with me dumping some prototype on Github, sometimes even with an open source project that I commit to maintain over a long time.
Two years ago, for the first time, I pursued a project idea which should not be open-source but a commercial SAAS product. It grew out of the Doctrine teams desire to synchronize Github Pull Requests with our Jira instance: A workflow engine for HTTP services. If this, then that (IFTTT) already existed at that point, but was far too limited for my use-case. I wanted something to allow:
I started developing this in my free time based on PHP, Symfony2, CouchDB, PostgreSQL and Backbone.js and got a prototype working early. However instead of reaching the state where I could release the project to others I hit some hurdles:
Last year in July, when I finally had something remotely usable Zapier hit the market with a beautiful product and support for gazillions of services. At that point my service just had support for Github, Twitter and Jira and for generic HTTP POST requests and a UI that could not be operated by anyone else but me. I was quite demotivated that day I found out about Zapier.
Nevertheless I continued to work on the project and tried to make it even more powerful than Zapier, by introducing more features that neither IFTTT nor Zapier had. Adding this complexity ended up being the nail into the coffin of the project.
Each week I worked less and less on the project, because I couldn’t find the motivation. When Zapier got funded in October I was both sad and happy: Apparently my idea was a good one, however somebody else executed this idea much better than myself. I stopped working on the project that week.
Today I took the day to migrate the Doctrine Pull Request workflow to a simple hardcoded application and disabled my projects website entirely.
I want to use this moment to share my personal lessons learned:
Choosing a scope that allows you to finish a working prototype within 1-2 months is an important key to success.
The longer it takes to get something working and useable for others, the less motivation you have. I know from my open-source experience that people using your project is a huge motivation boost.
The side projects I started since last October are much smaller in scope.
You can actually get burned out by a side project: by designing its scope way too big.
You cannot compete feature-wise with startups that put their full attention into a project from morning to night. Either make something small working better than commercial products or quit your job and put your full time into this.
Side projects are either about learning new technologies or about trying to build something commercially successful. Don’t try to combine this or you might get frustrated by choosing the wrong technology for the job.
Never ever use an existing open-source library as the core of your complicated business domain. If your domain is something remotely interesting you will fail to achieve your goals with the restrictions of the library.
Starting a big project alone is not a good idea. I found out that discussing ideas with people is very valuable and at the point where I started sharing my idea with others I was already too far into the project to be able to take most of the advice into account.
Keeping a project idea secret is completely useless. Others will come up with the same idea regardless. People have ideas all the day, however nobody ever has time to implement them. When they do, execution is even more important than the idea itself.
What are your lessons learned from failed side projects? I would be happy to hear other stories.
On last years SoCraTes Conference I had the pleasure to meet Sandro Mancuso from the London Software Craftsmanship Community (LSCC). Following his Twitter account I stumbled upon a meetup concept called “Code & Coffee” which the LSCC organizes very regularly. At a “Code & Coffee” developers would meet up early in the morning before work to discuss and hack at some coffee place.
I liked the idea very much and started such an event in Bonn. Our first test-event was a success, so that we now open up the concept to anyone who wants to join.
There is a Google+ Community Code & Coffee Bonn where you can join and get regular invites to the events.
Our next event is on March 26th. For more details see the Google+ page.
Looking forward to seeing you there!
Over at the easybib/dev Blog Anne posted an entry about their usage of Doctrine Repositories with a growing amount of query responsibilities. I want to respond to this blog post with two alternative approaches, because I have seen the easybib approach multiple times in different projects by different teams and think it can be approved upon a lot.
The problems with the approach outlined are:
The Repository API does not hide implementation details of the ORM, the QueryBuilder API is returned to the client code. This might seen like nitpicking, however it leads to bloated client code doing the query builder work over and over again. For example the ->getQuery()->getSingleResult(AbstractQuery::HYDRATE_ARRAY) call.
Different parts of the QueryBuilder filtering cannot be composed together, because of the way the API is created. Assume we have the filterGroupsForApi() call, there is no way to combine it with another call filterGroupsForPermissions(). Instead reusing this code will lead to a third method filterGroupsForApiAndPermissions().
This can lead to combinatorial explosion of methods that the developer using the repository needs to know. And wading through a list of 100 methods to find the right one is never fun, most importantly when the naming of methods is imprecise.
Generally introducing a new object such as a repository should pass the “Composite is simpler than the sum of its parts” rule. However the approach also clearly demonstrates a bad abstraction. In OOP the primary goal is avoiding changes to affect the whole system.
Instead of using the QueryBuilder outside of the Repository, lets start with an alternative refactoring. I will introduce a Criteria class for the User:
<?php
class UserCriteria
{
public $groupId;
public $hydrateMode = Query::HYDRATE_OBJECT;
}
It is important not to introduce a constructor here, because when we add more and more criterions, the constructor will get bloated. Static factory methods that create a criteria do make sense however.
Now we can introduce a match method on the UserRepository. Lets see that on an interface level first, to see how simple usage is for the client side of the repository:
<?php
interface UserRepository
{
/**
* @param UserCriteria $criteria
* @return array<User>|array<array>
***/
public function match(UserCriteria $criteria);
}
Put in a $criteria get back users or array data. Very nice and simple! The implementation would look like this:
<?php
/**
* @param UserCriteria $criteria
* @return array<User>
***/
public function match(UserCriteria $criteria)
{
$qb = $this->createQueryBuilder('u');
if ($criteria->groupId !== null) {
$this->matchGroup($qb, $criteria);
}
return $qb->getQuery()->getResult($criteria->hydrateMode);
}
private function matchGroup($qb, $criteria)
{
$qb->where('u.group = :group')->setParameter('group', $criteria->groupId);
}
The benefit here is, that we can add additional conditions and processing by only adding a new property on the UserCriteria and then handling this inside UserRepository#match(). Additionally you can save the UserCriteria in the session, or even in the database to that users can “save filter” or return to a search overview, with the previous criteria still known.
The client code now looks like:
<?php
$criteria = new UserCriteria();
$criteria->groupId = $groupId;
$criteria->hydrateMode = Query::HYDRATE_ARRAY;
$groups = $app['orm.ems']['api']
->getRepository('EasyBib\Api\Entity\User')
->match($criteria);
What we achieved in this step, is a simple API for the developer using the Repository and a simple way to compose conditions by setting new properties in the criteria.
If you complain that the solution has the same amount of lines, than the original EasyBib solution, then you are missing the point. We have factored away a violation of the Law Of Demeter and calls on an API (Doctrine) that should be implementation detail of the repository.
Lets try this by adding a new filter criteria, for example permissions I mentioned before:
<?php
class UserCriteria
{
const PERMISSION_READ = 'read';
const PERMISSION_WRITE = 'write';
//...
public $permissions;
}
class UserRepository
{
public function match(UserCriteria $criteria)
{
// ...
if ($criteria->permissions !== null) {
$this->matchPermissions($criteria);
}
// ...
}
}
Simple enough, now we can use it everywhere we want by adding for example $criteria->permissions = UserCriteria::PERMISSION_WRITE in our client code.
The Criteria object gets us very far in abstracting lots of query building behind a very simple API, but it fails short when:
The Specification pattern solves this issue. There are several ways to implement it, in the spirit of refactoring I will approach it from our existing Criteria.
Lets move the QueryBuilder code from the repository, into the Criteria object and rename it UserSpecification. Its important here to change the query builder code to use expressions that can be composed.
<?php
class UserSpecification
{
public $groupId;
public $hydrateMode = Query::HYDRATE_OBJECT;
public $permissions;
public function match(QueryBuilder $qb, $dqlAlias)
{
$expr = "1=1";
if ($this->groupId !== null) {
$expr = $qb->expr()->and($expr, $this->matchGroup($qb));
}
if ($this->permissions !== null) {
$expr = $qb->expr()->and($expr, $this->matchPermissions($qb));
}
return $expr;
}
public function modifyQuery(Query $query)
{
$query->setHydrationMode($this->hydrateMode);
}
private function matchGroup($qb)
{
$qb->setParameter('group', $this->groupId);
return $qb->expr()->eq('u.group', ':group');
}
private function matchPermissions($qb)
{
// ...
}
}
The repository is then delegating the expression generation and puts the result into the where() method of the builder
<?php
class UserRepository
{
public function match(UserSpecification $specification)
{
$qb = $this->createQueryBuilder('u');
$expr = $specification->match($qb, 'u');
$query = $qb->where($expr)->getQuery();
$specification->modifyQuery($query);
return $query->getResult();
}
}
Strictly speaking, the UserSpecification violates the single responsibility principle, which prevents the composability of specifications and reuse in different repositories. This is apparent by the $expr = "1=1"; line that is required to make the combination of conditions possible. Lets factor away the violation of the single responsibility principle by introducing three specifications:
<?php
interface Specification
{
/**
* @param \Doctrine\ORM\QueryBuilder $qb
* @param string $dqlAlias
*
* @return \Doctrine\ORM\Query\Expr
***/
public function match(QueryBuilder $qb, $dqlAlias);
/**
* @param \Doctrine\ORM\Query $query
***/
public function modifyQuery(Query $query);
}
class AsArray implements Specification
{
private $parent;
public function __construct(Specification $parent)
{
$this->parent = $parent;
}
public function modifyQuery(Query $query)
{
$query->setHydrationMode(Query::HYDRATE_ARRAY);
}
public function match(QueryBuilder $qb, $dqlAlias)
{
return $this->parent->match($qb, $dqlAlias);
}
}
class FilterGroup implements Specification
{
private $group;
public function __construct($group)
{
$this->group = $group;
}
public function match(QueryBuilder $qb, $dqlAlias)
{
$qb->setParameter('group', $this->group);
return $qb->expr()->eq($dqlAlias . '.group', ':group');
}
public function modifyQuery(Query $query) { /* empty ***/ }
}
class FilterPermission implements Specification
{
private $permissions;
public function __construct($permissions)
{
$this->permissions = $permissions;
}
public function match(QueryBuilder $qb, $dqlAlias)
{
// ...
}
public function modifyQuery(Query $query) { /* empty ***/ }
}
Now we need a new And-Specification to combine this in our code. This looks rather abstract and complex on the inside, but for clients of this object, the usage is simple and obvious.
<?php
class AndX implements Specification
{
private $children;
public function __construct()
{
$this->children = func_get_args();
}
public function match(QueryBuilder $qb, $dqlAlias)
{
return call_user_func_array(
array($qb->expr(), 'andX'),
array_map(function ($specification) use ($qb, $dqlAlias) {
return $specification->match($qb, $dqlAlias);
}, $this->children
));
}
public function modifyQuery(Query $query)
{
foreach ($this->children as $child) {
$child->modifyQuery($query);
}
}
}
Assuming we import all specifications from a common namespace Spec, our client code will look like this:
<?php
$specification = new Spec\AsArray(new Spec\AndX(
new Spec\FilterGroup($groupId),
new Spec\FilterPermission($permission)
));
$groups = $app['orm.ems']['api']
->getRepository('\EasyBib\Api\Entity\Group')
->match($specification);
In contrast to the criteria, we could now implement or and not specifications to enhance query capabilities.
You can now introduce reusability across different repositories by adding functionality to check if a specification supports a given entity.
<?php
interface Specification
{
// ..
/**
* @param string $className
* @return bool
***/
public function supports($className);
}
Every composite can delegate this operation to its children, and every leaf of the tree can return true or false. The Repository can then check for a valid specification in its match method:
<?php
abstract class EntitySpecificationRepository
{
public function match(Specification $specification)
{
if ( ! $specification->supports($this->getEntityName())) {
throw new \InvalidArgumentException("Specification not supported by this repository.");
}
$qb = $this->createQueryBuilder('r');
$expr = $specification->match($qb, 'r');
$query = $qb->where($expr)->getQuery();
$specification->modifyQuery($query);
return $query->getResult();
}
}
Now we can introduce very generic specifications, such as OnlyPage($page, Specification $spec)` for limit queries, or Equals($field, $value). For more readable code, you can then create a domain language for your specifications that is composed of more simple specifications:
<?php
class PowerUsers implements Specification
{
private $spec;
public function __construct()
{
$this->spec = new OnlyPage(1, new AndX(
new UsersWithInteraction(),
new EnabledUsers(),
));
}
public function match(QueryBuilder $qb, $dqlAlias)
{
return $this->spec->match($qb, $dqlAlias);
}
public function modifyQuery(Query $query)
{
$this->spec->modifyQuery($query);
}
public function supports($className)
{
return ($className === 'EasyBib\Api\Entity\User');
}
}
$top20powerUsers = new Spec\PowerUsers();
Hiding this kind of composition inside another specification allows you to reuse query logic in different places in the application easily and in terms of the domain language.
One reasons outlined by Anne for this design is testability: Because the Repository returns the QueryBuilder you have access to the generated SQL. However testing Doctrine Repositories should never be verifying the generated SQL. I see a lot of people doing this and it is very fragile and dangerous. Doctrine is a third party library and as such a rather complex one. Possible changes that break the test are:
These are 4 changes that have absolutely nothing to do with the feature you are actually testing, making the test code very fragile. In terms of abstraction SQL generation is an implementation detail of the Doctrine ORM and you as developer are only interested in the public API, which the SQL generation is not part of.
The code should really be tested against Doctrine itself. Since you are using Doctrine to get rid of SQL query generation for some use-cases, why should you use them as measure of quality in your testing efforts.
Testing repositories with the Specification pattern is testing the different specifications in isolation against a real Doctrine database backend. This will not be super simple to setup, but the isolation of specifications and their reusability across repositories actually allows us to keep the number of tests very small. The pattern avoids the problem of combinatorial explosion of test-cases very neatly.
The real benefit of testability is achieved in tests of repository client code. Before we were not able to unit-test this code, because of the Doctrine EntityManager, Query + QueryBuilder dependencies. Now We can inject the repositories into our controllers and services and then use mock objects in the tests.
Symfony2 is an extremely extendable framework, everything is extendable or overwritable through the Dependency Injection Container. The problem developers face is knowing about the extension points and when to use them. If you don’t know the extension points, your Symfony application will end up with code duplication, too much inheritance and very little unit-testable code.
This blog post will be the first in a series, describing Symfony2 extension points that help you achieve clean and duplicateless code. In my experience, using Symfony extension points to avoid code duplication helps you avoid writing thousands of lines of code in your controllers.
Inside controllers you can easily end with lots of duplication using the same general finder logic again in several actions. Take this following example:
<?php
class UserController extends Controller
{
public function showAction($id)
{
$dql = "SELECT u, d, a
FROM MyBundle\Entity\User u
JOIN u.details d
JOIN u.addresses a
WHERE u.id = ?1";
$user = $this->get('doctrine.orm.default_entity_manager')
->createQuery($dql)
->setParameter(1, $id)
->getSingleResult();
if ( ! $user) {
throw new NotFoundHttpException();
}
return array('user' => $user);
}
}
If we need this block of code in several actions of different controllers, we will end up with duplication that has to be eliminated.
One way of resolving the duplication appearing in this case, is moving the finder + not found logic into a common controller base class or into a trait. But this leaves us with a helper method buried in the code and a static dependency to a base class or a trait that we want to avoid.
<?php
class AbstractController extends Controller
{
protected function findUser($id)
{
$dql = "SELECT u, d, a
FROM MyBundle\Entity\User u
JOIN u.details d
JOIN u.addresses a
WHERE u.id = ?1";
$user = $this->get('doctrine.orm.default_entity_manager')
->createQuery($dql)
->setParameter(1, $id)
->getSingleResult();
if ( ! $user) {
throw new NotFoundHttpException();
}
return $user;
}
}
There are two problems with this sort of refactoring:
The SensioFrameworkExtraBundle offers an extension hook called Parameter Converters to transform Request attributes to objects directly for controller method arguments. They hook into the kernel.controller event that you can use yourself to achieve the same goal.
Lets see how the action will look like after our refactoring:
<?php
class UserController extends Controller
{
public function showAction(User $user)
{
return array('user' => $user);
}
}
Very concise and easy to read. The param converter doing the heavy lifting looks like this:
<?php
namespace MyProject\Request\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Doctrine\ORM\EntityManager;
class UserParamConverter implements ParamConverterInterface
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function apply(Request $request, ConfigurationInterface $configuration)
{
$id = $request->attributes->get('id');
$dql = "SELECT u, d, a
FROM MyBundle\Entity\User u
JOIN u.details d
JOIN u.addresses a
WHERE u.id = ?1";
$user = $this->get('doctrine.orm.default_entity_manager')
->createQuery($dql)
->setParameter(1, $id)
->getSingleResult();
if ( ! $user) {
throw new NotFoundHttpException();
}
$param = $configuration->getName();
$request->attributes($param, $user);
return true;
}
public function supports(ConfigurationInterface $configuration)
{
return "MyProject\Entity\User" === $configuration->getClass();
}
}
Now we only need to register this class in the dependency injection container:
<service id="my_project.user_param_converter"
class="MyProject\Request\ParamConverter\UserParamConverter">
<argument type="service" id="doctrine.orm.default_entity_manager" />
<tag name="request.param_converter" converter="user" priority="10" />
</service>
With the priority configuration the User entity is now always handled by our custom param converter and not by the default Doctrine converter.
In a next step, we should extract the query logic from the ParamConverter into a custom Doctrine entity repository. But that is a task for another blog post in this series.
I often get asked how you can use Doctrine2 and implement the SOLID principles at the same time. It bugs me having to reply: It is not really possible. Because Doctrine2 does not support value-objects (or embedded-objects), it is very hard to pull the Single Responsibility Principle off.
These problems are related to the inability to share behavioral code through aggregation and the complexity of state transformations. Combining both, your average entity with 5-15 fields can end up with hundreds or thousands lines of code. The solutions to both problems boil down to minimizing duplication and maximizing clarity.
Entity classes responsibility are the state transformations of their internal fields. This can simply be done by using setter methods or when avoiding setters, with use-case driven methods. These state transformations can be part of different responsibilities, specifically when properties belong to different groups of concepts.
Take a very simple entity that contains updated/created at logic:
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
**/
class Person
{
/**
* @ORM\Column(type="datetime")
**/
private $createdAt;
/**
* @ORM\Column(type="datetime")
**/
private $updatedAt;
public function __construct()
{
$this->createdAt = new \DateTime("now");
$this->updatedAt = new \DateTime("now");
}
/**
* @ORM\PreUpdate
**/
public function updatedAt()
{
$this->updatedAt = new \DateTime("now");
}
}
If you want to duplicate this logic to another second entity, then in Doctrine the solution for this is using traits. Kore will dismiss this solution, because traits create a hard dependency. Even if we accept the static dependency, traits are not perfect even for this very simple example, because its very likely that you cannot override the constructor of every entity.
The solution is to extract a value object Timestamped that contains all the logic:
<?php
class Timestamped
{
private $createdAt;
private $updatedAt;
public function __construct()
{
$this->createdAt = new \DateTime("now");
$this->updatedAt = new \DateTime("now");
}
public function updatedAt()
{
$this->updatedAt = new \DateTime("now");
}
}
class Person
{
private $timestamped;
public function __construct()
{
$this->timestamped = new Timestamped();
}
}
See how all the code could be moved into Timestamped and is now reusable in other entities.
Doctrine has no support for embedded objects, which is very sad. I am working very hard to get this feature into Doctrine as soon as possible. You can use the “object” type as a workaround and serialize() the value object into the database. However this is beyond ugly in my opinion.
Once you have identified groups of fields that are modified, then the complexity of the state transformations can attract lots of code.
Take an Order object that has a method for calculating the shipping costs, depending all the order items and products. To separate calculations from state transformations you can extract method objects instead of inlining the code into the Order object.
For this kind of extraction I create a folder Order and put all the extracted method objects in the Order subnamespace.
<?php
namespace MyProject\Entity {
class Order
{
public function calculateShippingCosts()
{
$calculator = new ShippingCostCalculator();
$this->shippingCosts = $calculator->calculate($this);
}
}
}
namespace MyProject\Entity\Order {
class ShippingCostCalculator
{
public function calculate(Order $order)
{
return 0;
}
}
}
From this step its easy to make the code reusable by passing the shipping cost calculator:
<?php
class Order
{
public function calculateShippingCosts(ShippingCostCalculator $calculator)
{
$this->shippingCosts = $calculator->calculate($this);
}
}
Another benefit is that you can test the shipping cost calculator directly in a unit-test and avoid checking for the correctness indirectly through a getter method for the shipping costs.
Extracting every method of an entity into a method object is obviously overkill. You should exercise caution and common sense when performing this refactoring.
Not all the techniques to implement SOLID code can be exploited when using Doctrine for technical reasons. In the future I hope to support value objects in Doctrine to make this possible.
Continuing my series on PHP PaaS Clouds (Fortrabbit), I turn to Microsoft Azure today. After some research I found out Azure supports post deployment hooks to run Composer and allows you to configure environment variables from the Management console.
Microsoft launched Azure Websites in June this year. It is a platform as a service solution where you can deploy your websites via FTP or Git. With Azure Websites you can avoid having to deal with the complex deployment automation that is necessary for Azure Hosted Cloud Services. As long as your website only requires an SQLServer, MySQL or external APIs you can actually achieve quite a lot already.
For a Symfony2, Silex or any other modern project however you want Composer support during the deployment as long as failures with Composer don’t break your site.
It turns out that Azure Websites - to support other platforms that require compiling - actually has an extremely robust deployment system (as far as I understood its internals). The Git repository is separated from the actual code that is served from the webserver and a number of old checkouts is kept to allow rollbacks through the Web interface. Once a Git push was recognized, Azure websites will execute a build step, and then copy all the files over to a directory with the name of the Git SHA hash. This directory is then symlinked to the document root.
If Composer fails during this step, the website will still be served from the currently running version and you don’t have to face unexpected downtime.
To actually run Composer as a post-deployment tool you have to do some manual work. Create a .deployment file in your project root folder:
[config]
command = "D:\Program Files (x86)\PHP\v5.3\php.exe" build_azure.php
If you are using PHP 5.4, then you probably have to change the command version name to “v5.4”, but I haven’t tested this.
Then you need to create the build_azure.php file that is referenced in the deployment command. The actual implementation is up to you, my version is the most simple one:
<?php
if (!file_exists("composer.phar")) {
$url = 'https://getcomposer.org/composer.phar';
file_put_contents("composer.phar", file_get_contents($url));
}
$_SERVER['argv'][1] = "update";
$_SERVER['argv'][2] = "--prefer-dist";
$_SERVER['argv'][3] = "-v";
require "composer.phar";
Note
This currently only works with a Composer version, where PR-1341 is applied. You can check out my Composer fork and run ./bin/compile to generate a composer.phar that works.
Instead of using this approach, you could ship composer.phar with your repository for example. You can of course execute additional steps in the build_azure.php, for example warmup caches.
I wanted to host a simple application to play around with the Tent Protocol (see my last blogpost), so I checked through some of the PHP Cloud providers again for the fun of it. One requirement was to deploy from Git and update dependencies from Composer. I found a new provider that i haven’t heard of before, Fortrabbit that supports this so I had to check it out. It has some more features that I really dig:
Fortrabbit provides you with a Git url where you can push your repository. It is directly deployed during the push operation. You can trigger composer updates by having a special syntax in the commit message. The push output informs you about all the steps performed during deployment.
Additionally you can configure environment variables in the web-administration interface that are available in the application through $_SERVER. You can easily use them to configure your application, if its hosted in a public repository. Great to share sample applications on Github and host them from there.
You get SSH access to the machines, where you can take a look at the apache and php error log files. You have vim available. Quite cool and very helpful for any kind of debugging necessary. Deployments overwrite every change you make, so its still a save environment.
The composer support allows for post install scripts, which is cool to perform all sorts of cache warmup and other deployment tasks.
You can host one application for free, however they shutdown after 48 hours if you don’t regularly click on a reset button. Its definitely enough to get small prototypes up and running. From there you can upgrade in many small steps from small plans (10€/month) to bigger ones (80€/month).
Over the weekend I built a very simple bookmarking application for tent.io. I wanted to try the tent functionality to create arbitrary entities of data using something as simple as a “Bookmark”.
The application retrieves and stores bookmarks on your own tent-server, nothing is kept on the applications server and as a user you keep full control over your content (bookmarks).
The code for the application is on Github, as well as the TentPHP library I have written to support the protocol. The application is using PHP, the Silex microframework and MySQL.
About two month ago a new distributed social networking protocol was launched called Tent.io. It works over HTTP using JSON and distributes data using webhooks. This happened in the shadow of app.net funding, just two weeks after they collected over 500k USD. Tent.io got lots of attention but not as much as app.net sadly. Its distributed nature however is much more suited to achieving true independence of large companies and true privacy for the users though. Compared to Diaspora it has the benefit of being a protocol, not an application first.
Now two month later, there are reference implementations for Server, Client and a Twitter like Status application. You can use Tent.is to create a free or payed tent account including access to the status application or setup your own tentd server on Heroku.
As a user I can connect any application to the tent server I have registered with and control the visibility and sharing policies. Content can be private, public or visible to certain groups only. A Tent server then makes sure to distribute content to the appropriate subscribers.
In this early state of the protocol it makes sense to register on the central tent.is service, however when the server gets more stable or alternative server implementations popup its easy to move all your data off tent.is to your own server. One feature that will hit tent.is soonish is registration of domain records. That will be the first step to your own tent server, I am eagerly waiting to host all my content at https://tent.beberlei.de at some day.
Right at the moment the tent software stack is developed by the team that also hosts Tent.is. If all you can provide is money, then signing up for the 12 USD per month is the way to go.
If you are a developer, then take a look at the Wiki where related projects are listed. You will find a bunch of client libraries for major languages already, helping you to get started.
I suppose the major work lies in implementing Status-Post clients for all major smartphone platforms and desktops. As well as the host of applications that Facebook and other social networks provides: