Behat and “The current node list is empty.” error.

If your receiving the error “The current node list is empty” while using Behat, then likely your project is returning an HTTP 500 error. This may be because your bundle depends on some other bundle not available in your test environment. This was the case when for me when testing a bundle on travis-ci and i was not able to find documentation on this error.

One solution as suggested on github is to try dumping the contents of the scraper/browser to see what kind of error your getting.

However that will likely not give you any output if the server is returning an HTTP 500 internal server error. Your best bet is to just check your logs and do a search for any errors.

If your trying to run your functional tests on travis-ci then you might want to check out this great article on running Behat scenarios in isolation of your project.

Best of luck.

Simple Method for Checking for Order With Behat

While needing to write a test to check the order of 2 items (within a given CSS query) in Behat, I did a little googling and came across this website here.

The tutorial is great and i just wanted to give a shout out to the author for their great content. I also made a slight change to include testing for the existing of the 2 items.

Here is my slightly updated version:

You can see an example of the test i wrote using this method here.

Sorting/Reording Symfony2 Entities Display Order.

So i had to implement a mechanism to re-order Categories and also Boards for my forum bundle, and with though there are many ways to go about it, here is how i solved the problem of reordering them. The reordering functionality is circular so last items getting pushed down end up on the top of the list, and top items getting pushed up end up on the bottom of the list.

What do you guys think? Know of a better approach? Let me know!

Custom Validators on Validation Groups in Symfony2.

If you are using validation groups and have created a custom validator, you will want to use it in your validation group, however its a bit different from how you would apply validators in the entity, and quite similar in-fact to how you define services.

Its similar to how you define services because you have 2 root nodes, first somewhat like services.yml’s parameters line, in this instance called ‘namespaces’, the second part matches the entities name which the validator will be applied to.

Starting out, your validator.yml file probably looks like this:

This is an example taken from my AttachmentBundle, which you can find here.

Now, when we have a custom validator, in this case, some validators to check a users quota on file uploads etc, we need to set a namespace for our custom validators, with the namespace parameter, and then reference that namespace below followed by our custom validator.

The name of the validator must be wrapped in double quotes so that Symfony2 is aware that this is using a custom validator, inside of which we first start the namespace, and secondly the validator alias.

We define the alias of our validator in our services.yml like so:

Symfony2 Voter Access Decision Strategy Explained!

The voter access decision strategy can be set in your Symfony2 app/config/security.yml. You have the choice of 3 approaches (Unanimous, Affirmative, Consensus). Set your strategy to  1 of them 3.

The approach of each is explained below.

  • Unanimous = 1 single voter denies access.
  • Affirmative = 1 single voter grants access.
  • Consensus = Majority wins.

So in Unanimous, if a single voter denies access, all other voters decisions are overridden and the bottom line is you will be denied access. If however you use Affirmative, a single voter only needs to grant access to override and the regardless of how many voters block you, you will always be granted access so long as a single voter permits it. Consensus, lastly; will weigh up and balance the number of denies or accesses being granted and decide that with the most voters wins. To put the Consensus another way, if more than half the voters grant access, then you have access. If more than half the voters deny access, then access will be denied.

Remember to return 1 of the 3 access types, the choices you have are:

Abstain will be impartial when using the consensus strategy for your security configuration.

You can set your class to be used, and listened for by the voting service in your bundles config, like so:

Authorisation on Roles in Symfony2

Following a discussion on the IRC room from someone who viewed my post about login/logout handlers in SF2, i wanted to clarify that when dealing with Roles, they should be dealt with in the controller actions.

For off, you need to make sure you got the right hierarchy of roles. In your app/config/security.yml you need something following the structure of:

Where the lowest level of access is at the top and the higher levels of access envelope the last levels of access.

Then you inside your controller actions you would do:

According the order of the role hierarchy if you have the role or higher than specified the controller action will continue, if you have a lower level of access than the minimum required then you will get an AccessDeniedException.

Redirecting on login/logout in Symfony2 using LoginHandlers.

Using login handlers or even logout handlers, we can do a number of last minute things before the user is redirected to where they need to go. Being able to intercept the redirect at the last minute and make the user get redirected elsewhere is relatively simple.

Firstly though, i notice a lot of people now who are using Symfony 2 are cheating somewhat by using an EventListener and registering it with the security.interactive_login event listener. This is not the best way to go about this, namely because this event listener is not intended for this purpose. Sometimes event listeners are not the best way to go because they were defined for a specific purpose other than your intention and using them may have undesirable side effects you may not notice right away. Using handlers however allows a little more flexibility in that in all likelihood regardless of changes to Symfony in future revisions, they should still work and were designed specifically for the purposes we will need them for.

Firstly, we need to define our services, personally, i am a fan of YAML, so i define my services as such but feel free to do the same in XML:

Now our services are defined, we need to define the handlers themselves. I like to create a directory named Services in my user bundle for this purpose, then create 2 files. The first file is LoginSuccessHandler, the second is LogoutSuccessHandler. Our handlers will implement the appropriate interface for either our login or logout handlers, which require usually only one method in these instances.

Here is what the login handler should look like:

Note my namespace is CCDNUser, and my bundle is called SecurityBundle, so our service is named ccdn_user_security.component.authentication.handler.login_failure_handler. Change this to your own namespace and bundle name accordingly but ensure to use the same format as used here, underscore your namespace and append the bundle name with an additional underscore without the term ‘bundle’ in it. Failure to get this part correct will mean your namespace will not be loaded and you will get problems later on in this tutorial as exceptions will be thrown regarding the service not existing.

Here is what the logout handler should look like:

Our service definitions inject some of the classes we need to make use of our handlers, namely a Router object and the SecurityContext object, we can store these in member variables for later use. Then we wait for the onAuthenticationSuccess method to be called in our LoginSuccessHandler, once this has happened, we have a request and token interface object at our disposal. Using the security context object we can determine what role they have (i.e; ROLE_USER, ROLE_ADMIN etc) and appropriately redirect them as needed.

I like to redirect members of ROLE_USER role to where they came from prior to logging in. This is achieved by passing the ‘referer’ header into the redirect response object we return. I took this step both in the login and logout handlers.

Last thing we now need to do, is inform our security config that it needs to use these handlers by doing the following:

In this instance i am using FOSUserBundle and extending it in my own UserBundle, though this code is contained in the SecurityBundle. Which is probably the best way to do this. As the handlers used here work in any bundle because they plugin to Symfony2 core and implement their login handlers, and should not be dependant on any user bundle.

You can see a complete implementation of this in my security bundle found on github

Once this is implemented your on your way to a better login/logout system. Enjoy.

Creating embedded forms in Symfony 2.0

If you are looking to create a form from 2 or more entities, like i have been then you probably find the documentation somewhat lacking and confusing. If you follow the guides you can get your form working if you start from the least dependant entity making that the first entity you use to build your form from your controller. I find if you start from the most dependant you usually get all manner of errors.

What i have is a basic forum i am working on, in my current form situation i have 3 entities, Board entity, a Thread entity and a Post entity. If you start by creating your form with Board then chances are it won’t work, i created my forms in separate ‘Type’ classes (PostType.php ThreadType.php and BoardType.php) and then created my PostType form in my controller, which then sorts out its dependencies on its own.

My controller class is very basic and not very polished, but here is what it looks like:

It probably looks somewhat messy as i say, its a rough work in progress, but it works, and here are the FormTypes i used, starting with; PostType.php:


And lastly, the BoardType.php

Notice how i added a constructor, this is so we can easily chain feed in from the first object any changes to the form, such as wether we wish to bother including a field or not, we can opt to have any field removed if the form is used under different circumstances such as different access controls for different users with different permissions or if the form is used in another way on the site.

One more thing we need to make sure, is that all the references in our entities make use of the cascade={“persist”} option so that it maintains relations between the relevant forms as new ones get processed, so if say a thread does not exist then when processing the post, it should create one and do the association for us.

Here is an example of a snip from my Post entity class Post.php

Lastly, you will need a formHandler if your not working in your controller, if using my example code then the postFormHandler.php looks like this: