Welcome on my blog

On this blog I try to regularly talk about my experiences with development. To be honest, I tried this before, more than once... But this time it will be different!

This time I'm going to make a list of stuff I want to talk about, and I'm setting a weekly reminder in my agenda to write a blogpost and/or think about more subjects.

Latest posts

PHPCR: Reading and writing2013-11-27

This post is the second in a serie about PHPCR with Jackalope. If you want to know more about PHPCR, I recommend watching the slides about PHPCR.

In the previous post, I talked about setting up your repository. In this post we will start playing with some actual content.

Insert data

To show the basic usage of PHPCR, we are going to load some data into our repository. For this I used Faker.

$ composer require fzaninotto/faker ~1.2

Because we are going to add more CLI scripts later on, I created a simple Symfony Console Application for this. I called it console at placed it in the root. You can find the console and the Command on Github.

With PHPCR, it is pretty easy to create new nodes. You simply call addNode on it's parent node. So before we can create new nodes, we need to rootNode. You can request the rootNode from the PHPCR session.

$session = $this->getHelper('phpcr')->getSession();

Here we use the helper that we defined in cli-config.php in my previous post to get the Session. Now we have the session, we can simply retrieve the rootNode with $session->getRootNode(); With the rootNode, we can start creating fake nodes.

$faker = \Faker\Factory::create();
while (count($rootNode->getNodes()) < 10) {

    try {
        $node = $rootNode->addNode($faker->word);

        $node->setProperty('title', $faker->name);
        $node->setProperty('body', $faker->text(1000));
    } catch (\PHPCR\ItemExistsException $e) {
        // Ignore, and try again


On line 5, you see the addNode, the first argument you give it, is the nodeName. You can give a second argument, to define the nodeType but in this case we will use the default value (which will be nt:unstructured). On line 7 and 8, we set 2 properties with random values. The first argument is the name of the property, the second is the value. You can also give a third parameter, to indicate the type, but this is not required as PHPCR will guess the type based on given value.

Because nodeNames need to be unique, Jackalope will throw a ItemExists Exception when we try to create 2 nodes with the same name. As that might happen with random date, we just catch the exception and try again.

Reading the data

Now we have some fake data, we can try to query it again. We start with simply iterating over all the childNodes. Because every Node implements Traversable, we can simply loop over a node to get its children.

foreach ($rootNode as $childNode) {
    $name = $childNode->getName();
    $title = $body = null;
    if ($childNode->hasProperty('title')) {
        $title = $childNode->getProperty('title')->getValue();
    if ($childNode->hasProperty('body')) {
        $body = $childNode->getProperty('body')->getValue();
    // .. do something

All pretty straight forward. To retrieve propertyValues, there are a few alternatives. You can, for example, use some of other property methods, to convert the property value to another type.

$dummyNode->setProperty('floatProperty', 3.1415);
$property = $dummyNode->getProperty('floatProperty');
var_dump($property->getString()); // string(6) "3.1415"
var_dump($property->getLong()); // int(3)
var_dump($property->getBoolean()); // bool(true)
var_dump($property->getBinary()); // resource(#) of type (stream)

Besides that, you can use $node->getPropertyValue('propertyName'). By passing the second argument, you can convert the value to the desired type.

$dummyNode->getPropertyValue('floatProperty', \PHPCR\PropertyType::STRING); // string(6) "3.1415"

Finding nodes

You can also retrieve a node by it's path or multiple nodes by an array with paths

$dummyNode = $session->getNode('/dummy');
$nodes = $session->getNodes(array('/', '/dummy'));

Or retrieve a childNode by it's name:

$dummyNode = $rootNode->getNode('dummy');
// Note that we call this on $rootNode, not on $session

You can even find nodes by searching with wildcards:


There is a lot more to learn about nodes and properties. In the following chapters some of those features will be explained. If you want to learn more about the possibilities, you might want to look at the PHPCR api tests.

In the next post, we will play with Queries and the QueryObjectModel.

Setup Jackalope with MySQL2013-11-16

This post is the first in a serie about PHPCR with Jackalope. If you want to know more about PHPCR, I recommend watching the slides about PHPCR.

In this post I will walk through the first steps, setting up your Content Repository using Jackalope. In this case we will use MySQL as storage, but in a future post, we will migrate our data to a Jackrabbit server.

Install Jackalope

First we will install Jackalope DoctrineDBAL. In this serie I will use composer, and in the examples I assume it's installed system wide, so the composer command is available.

$ mkdir phpcr-tutorial && cd phpcr-tutorial
$ composer require jackalope/jackalope-doctrine-dbal ~1.0

This will also install the base Jackalope package, the PHPCR and PHPCR-Utils packages and Doctrine DBAL (and their dependencies).

To already be a bit prepared for switch storage backend later on, I setup a basic configuration that allows us to switch easily later on. For this I installed symfony/yaml to parse the Yaml file.

$ composer require symfony/yaml ~2.3

The next step is to create your database and configure Jackalope with the correct transport layer.

Configure jackalope

Jackalope provides a file that gives us some powerfull CLI commands. For this to work, we need to tell Jackalope what repository connection we are using. Jackalope requires a cli-config.php file for that in the root of your project. In that file, we need to define the connection, but we can also add a HelperSet to the CLI. The HelperSet will contain the PHPCR session, so Jacklope CLI has something to talk to.

Luckily Jackalope provides an example file, so we see how the connection is created. (For Jackrabbit, there is a similar example file)

For this example, I created a bit of a revised version, to be prepared for the switch later. But you can choose to just use the example provided by Jackalope Doctrine DBAL if you like. The full file I created can be found at github. Below you will find the instantiation of the repository. Based on the config file, it's decided which Jackalope Repository is created. In this part we only implemented the Doctrine DBAL version.

use \Doctrine\DBAL\DriverManager;
switch ($config['jackalope']['transport']) {
    case 'jackalope-doctrine-dbal':
        $dbConnection = DriverManager::getConnection(array(
            /* database connection variables $config['jackalope']['dbal'] */

        $factory = new \Jackalope\RepositoryFactoryDoctrineDBAL();
        $repository = $factory->getRepository(array(
            'jackalope.doctrine_dbal_connection' => $dbConnection

    case 'jackalope-jackrabbit':
        throw new \Exception('Jackrabbit bootstrap has not yet been defined');
        throw new \RuntimeException(sprintf('Invalid transport "%s" given', $config['jackalope']['transport']));

After that we need to actual login to the repository to be able to read and write data.

$credentials = new \PHPCR\SimpleCredentials($config['phpcr']['username'], $config['phpcr']['password']);
$session = $repository->login($credentials, $config['phpcr']['workspace']);

$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
    'session' => new \PHPCR\Util\Console\Helper\PhpcrHelper($session)

Now we have the config file we can init the database.

$ ./vendor/bin/jackalope jackalope:init:dbal

Jackalope will tell you it has initialized the database tables.

Testing your repository

You should now have a working repository. We can test this by executing our first query, which should return the rootNode

$ ./vendor/bin/jackalope phpcr:workspace:query "SELECT * FROM [nt:unstructured]"

With this query, you request all notes with type nt:unstructed, which in this case, is only the rootNode. Now we're done with the first part. In the next part, we will start with reading and writing to the repository via Jackalope.

Symfony CMF2013-11-05

Today I got into a discussion about Symfony CMF. The discussion started with the question, if Symfony CMF isn't trying to create a solution for a problem that doesn't exists. That person thought CMF only solved a developers problem, but couldn't solve the problems for front-end developers or editors (or even added more problems). It came down to it, that he had seen the admin interfaces that come with Symfony CMF and saw that it was... less from perfect (to put it nice).

Goals of Symfony CMF

Symfony CMF aims to provide a toolbox to create your own custom CMS, not by reinventing the wheel, but by reusing existing code and sharing the produced code (parts of it will be used in Drupal 8). It aims to make it easier for developers to add CMS functionality to applications built on Symfony 2.


To do that, they looked at other solutions, solutions not limited to PHP, to structure content. This because a CMS has mostly unstructured data, and forcing this into a RDBMS isn't always a good fit. Graph database are a better fit. They found JCR, a Java specification that deals with content. They ported that to PHP and called it PHPCR; PHP Content Repository. With PHPCR, there is an API to interface with your content repository.

What is doesn't solve

Althought Symfony CMF does provide some basic admin interfaces (with Sonata Admin), it isn't meant as an end product. For most customers and editors, those screens just won't be enough. But there is nothing to stop you from developing your own admin screens that does fit you customers needs.

Symfony CMF isn't a solution aimed at the end-user, that is still you job as a developer, to implement a solution that helps your end-user and the editors. Symfony CMF just helps you to not get a panic attack when somebody tells you to add content management to your Symfony2 application.

For more information about Symfony CMF, check the bigger picture slides

So little time2013-10-04

As I mentioned 2 months ago, I believe it's important to keep developing yourself. You can't just sit there and repeat the same trick every time. I also told that I wanted to do that by trying to find a new job, and by attending more conferences and user groups.

But that all isn't that easy, I couldn't attend my user group because of a agenda conflict (and missing the next one as well) and conferences are just to expensive to pay for by myself.

The work part isn't much better as well. I shouldn't complain, I still have a job! But at that job it is hard to find a challenge, and there is a lot of repetitive work involved. And because there is a lot of Drupal involved, OOP isn't part of my daily routine anymore, and that sucks.

While searching for a new job, I have found a company were I really want to work. The first job interview went well and they are open to further conversation, but the sad part is, that they don't have a spot at this moment and they don't know on what term they will. And that's a pretty difficult time for me, I really want that job, but I'm not sure if I should wait for it. At this point I'm not even sure if I actually would get hired, so is it worth the risk?

And with all this, it's hard to keep myself busy on the level were I want to be (and grow from there), At work there isn't much room for it, and at home I can't spend the time at it that I would like (my wife would like some attention now and then :-) ). So I try to put some time in a JAVA project I started 6 months ago, at least I'm working on a OO project.

Any tips how to deal with such a time would be greatly appreciated! Sometimes I have the feeling I'm just not patient enough, that I should just wait, and be grateful I have a job.

My first uncon talk2013-09-15

About 2 months ago, when 010php started, I started playing with the idea of giving talks myself. At first I was pretty anxious to actually execute that plan. I talked with some people that I had the idea and they all encouraged me to do it. So I started writing down some ideas I already had. But until last week, I didn't actually had a talk planned anywhere.

But last Tuesday, Lineke asked me if I would give a uncon talk at PFcongres 2013, I don't think she new I was already playing with the idea, but she was very convincing and I said I would do my best to prepare something.

Because of limited time, I started to prepare the evening before the conference, at that point I hadn't even decided what subject I would choose for the talk... I decided on PHPCR and luckily the preperation went fairly well and I even rehearsed it once!

So yesterday the conference was there, and on my way in the train I even managed to talk myself into a calmer state. Don't get me wrong, I was still nervous as hell... just a bit less then before. I spoke to Linke en we planned my talk at 12.10. After that I just went to the talks, trying not to think about it to much anymore. At the talk just before my uncon slot, I got a bit nervous when Joshua already mentioned he didn't now if he would be done in time. Should I leave the talk early to be on time? Should I just leave with everybody else? Eventually I decided that I would leave 5 minutes before my talk started. That gave me some time to visit a restroom (to much coffee...), and still be on time for my talk. This meant I walked out while Joshua was still answering some questions (sorry for that), but it made me feel a bit better.

Giving the talk went pretty well, of course I forgot to bring a VGA connector, but I could use Lineke's (thanks!). I pretty much gave my talk as intended (only forgot to tell 1 thing), and got some good questions, so apparently people weren't bored to death :) Just before the end of my talk I noticed myself saying Uhh between pretty much every sentence, so I learned something while giving the talk!

After the talk Lineke already gave me some feedback (she noticed the Uhh's as well) and I spoke some people that had seen it. Another important thing I learned, is that a topic like PHPCR is very hard to explain, and nearly impossible to explain in 10-15 minutes, so next time I would probably want a 50min slot and I need to rethink how I can explain the subject to people that have no clue about it. On a sidenote: you can still comment on my talk, so please leave feedback!

All with all was it a great experience and I'm certain I will do it again. Maybe I'll even submit a actual talk to a conference next year.