Posts Tagged ‘symfony2’
Symfony2 MSSQL support with pdo_dblib
We now maintain a library for connecting to a MSSQL database, since we are using it in one of our Symfony2 applications. You can find the code here:
https://github.com/LeaseWeb/LswDoctrinePdoDblib
If you are trying to use Doctrine 2 (for Symfony 2) to connect to MSSQL server from a Linux machine, you might encounter the same problems we did. To be able to connect to MSSQL from a Ubuntu Linux server you will have to install “php5-sybase” (Sybase / MS SQL Server module for php5).
$ sudo apt-get install freetds-bin php5-sybase
Add the following lines to “/etc/freetds/freetds.conf”, and make sure you set it to talk the right MSSQL protocol. The TDS protocol version should be 8.0 for MSSQL server 2005 and up, which may be confusing. Also replace “{mssql-server-ip-address}” with your MSSQL servers IP address (without the brackets).
[mssql_freetds]
host = {mssql-server-ip-address}
port = 1433
tds version = 8.0
client charset = UTF-8
text size = 20971520
If you only connect to one server, you can also set the global TDS protocol version to 8.0 like this:
[global]
# TDS protocol version
tds version = 8.0
Now test that your freetds is working by using the command line client. You have to replace {username} and {password} with your username and password (without the brackets):
$ tsql -S mssql_freetds -U {username}
Password: {password}
locale is "en_US.UTF-8"
locale charset is "UTF-8"
using default charset "UTF-8"
1> quit
If you specify in “app/config/parameters.ini” that you want to use the “pdo_dblib” driver like this:
database_driver="pdo_dblib"
You will see the error:
[Doctrine\DBAL\DBALException] The given 'driver' pdo_dblib is unknown, Doctrine currently supports only the following drivers: pdo_mysql, pdo_sqlite, pdo_pgsql, pdo_oci, oci8, ibm_db2, pdo_ibm, pdo_sqlsrv
This is why you should install our LswDoctrinePdoDblib bundle, and following the instructions, you should comment out the “driver” and add a “driver_class” like this:
# Doctrine Configuration
doctrine:
dbal:
#driver: %database_driver%
driver_class: Lsw\DoctrinePdoDblib\Doctrine\DBAL\Driver\PDODblib\Driver
After that you should be able to run this command without any errors:
$ php app/console doctrine:database:create
Now do not expect everything to work flawlessly, since MSSQL is not officially supported, and Doctrine is very picky in what it does and does not accept as database structure. However, this should get you started. Post your experience and questions in the comments. Good luck!
7 habits for creating highly effective Symfony bundles
This article is about writing Symfony2 bundles and is based on the 7 habit for highly effective people by Stephen R. Covey.
Habit 1: Be Proactive
Take initiative in life by realizing that your decisions (and how they align with life’s principles) are the primary determining factor for effectiveness in your life. Take responsibility for your choices and the consequences that follow.
If you choose Symfony2, follow the best practices and believes rigorously, also read everything you can about it (and join meetups). Choose Symfony DI, choose Symfony security, choose Doctrine, choose APC, choose Symfony coding guidelines, (like PSR-0, PSR-1 and PSR-2 standards) and most important: choose other people’s bundles. Choosing Symfony’s best practices can be hard sometimes, because Symfony leaves many choices open and dictates less choices than other frameworks do (e.g. Rails).
Habit 2: Begin with the End in Mind
Self-discover and clarify your deeply important character values and life goals. Envision the ideal characteristics for each of your various roles and relationships in life. Create a mission statement.
What do you want to achieve, set goals, choose technologies and strategies without limiting you to what is available. This seems like a contradiction with the previous one, but I strongly believe you should find a balance: Choose the Symfony solution or someone else’s bundle (maybe even do a pull request to add any missing functionality) if you can, but do create your own bundle if you need to, do not compromise before you even started. If you have a clear and unique goal, you can craft your bundle to fulfill it.
Habit 3: Put First Things First
Prioritize, plan, and execute your week’s tasks based on importance rather than urgency. Evaluate whether your efforts exemplify your desired character values, propel you toward goals, and enrich the roles and relationships that were elaborated in Habit 2.
Have the guts to refactor when you need to and believe me: sometimes you need to. Also, make sure you do not accept bug reports unless you really have to. Often enough these are just feature requests that have urgency, but no importance. Following SCRUM, which has the same concept (work in order of importance), is not sufficient to achieve this habit, but may help you and give you a way of measuring progress.
Habit 4: Think Win-Win
Genuinely strive for mutually beneficial solutions or agreements in your relationships. Value and respect people by understanding a “win” for all is ultimately a better long-term resolution than if only one person in the situation had gotten his way.
Bundles do not only compete with each other, they also complete each other. Ownership of bundles can drive competition, which motivates, but open source will allow people to copy solutions from each other, which makes sure no effort has ever to be in vain. Even if a bundle is less popular it does not mean it is less important. Maybe it provided important functionality that was merged into the more popular bundle and this makes the author an major contributor.
Habit 5: Seek First to Understand, Then to be Understood
Use empathic listening to be genuinely influenced by a person, which compels them to reciprocate the listening and take an open mind to being influenced by you. This creates an atmosphere of caring, and positive problem solving.
Do not write your own bundle or criticize other people’s bundles before the understand what the available bundles offer and actually do. After you did that try to contribute in a positive manner, not by criticizing in comments, but by being positive and providing pull requests. But also when being criticized on your bundle, be positive and try to understand what people are actually saying and what their needs are. Negative comments may hold valuable information.
Habit 6: Synergize
Combine the strengths of people through positive teamwork, so as to achieve goals no one person could have done alone.
We can not create bundles alone, so let others help you and do help other people. Whether it is by providing support, contributing code or reporting bugs. All roles matter and all efforts should be appreciated with a positive attitude. I do not pretend to know why the Open Source paradigm works, but I do know it is all about “synergy” and that with Open source we can achieve goals that no single person could have achieved alone.
Habit 7: Sharpen the Saw
Balance and renew your resources, energy, and health to create a sustainable, long-term, effective lifestyle. It primarily emphasizes exercise for physical renewal, prayer (meditation, yoga, etc.) and good reading for mental renewal. It also mentions service to society for spiritual renewal.
The most important advice I heard about this point is: to sharpen the saw, be humble and start sawing. The reason for this is that a lack of experience and the Dunning–Kruger effect will make you grossly overestimated your performance and ability. It will make you become a victim of the seductive and destructive Not-Invented-Here syndrome. Sharpen the saw is about continuous improvement and especially in IT it is important to keep learning new things, because the technology moves fast. So do not hesitate and start creating Symfony2 bundles right now!
Symfony2 consistent routing
Software consistency in large teams is very important, because nobody likes whitespace or formatting commits or arguments about on which line brackets should be placed. Fortunately Symfony2 has a nice Standards Document that you can follow. PHP CodeSniffer can be loaded with the Symfony2 coding standard so that everybody can see the violations on the Continuous Integration (CI) server.
Unfortunately Symfony2 is not that strict everywhere. This lack of strictness allows a group of programmers to argue over and mess up a project. One of the discussions could be about naming routes. Symfony1 had a really nice option for “default routing”, allowing you to specify a single rule called “default” that had url: “/:module/:action/*”, but unfortunately that feature is not present in Symfony2. In Symfony2 we can either define routes individually or we can generate them using the CRUD generator (see my previous post). This is not a bad option as I will show below.
Naive routing
Routing to specific actions in controllers in Symfony2 can be put in a “routing.yml” file as described in the Routing section of the Symfony2 manual.
# app/config/routing.yml
product:
pattern: /product/
defaults: { _controller: AcmeDemoBundle:Product:index }
product_edit:
pattern: /product/edit/{id}
defaults: { _controller: AcmeDemoBundle:Product:edit }
It is easy to understand that this way the file becomes large and unless people agree on a very strict naming policy it needs to be consulted every time you want to make a link from a view or controller to any action.
CRUD generated routing
After using the CRUD generator to generate scaffolding for an Entity called “Product”,
maurits@pc:~/project$ app/console generate:doctrine:entity --entity=AcmeDemoBundle:Product ... Configuration format (yml, xml, php, or annotation) [annotation]: ... maurits@pc:~/project$ app/console generate:doctrine:crud --entity=AcmeDemoBundle:Product ... Do you want to generate the "write" actions [no]? yes ... Configuration format (yml, xml, php, or annotation) [annotation]: ... Routes prefix [/product]: ...
I edited my routing to include this rule:
# app/config/routing.yml
demo_bundle:
resource: "@AcmeDemoBundle/Controller/"
type: annotation
prefix: /
This is the only routing entry you need per bundle when using (CRUD generated) routing annotation in your controllers. The “@Route” and “@Template” annotations can be seen below:
/**
* Product Controller
*
* @Route("/product")
*/
class ProductController extends Controller
{
/**
* Lists all Product entities.
*
* @Route("/", name="product")
* @Template()
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AcmeDemoBundle:Product')->findAll();
return array('entities' => $entities);
}
// ...
}
Your routes will look like:
maurits@pc:~/project$ app/console router:debug
[router] Current routes
Name Method Pattern
... ... ...
product ANY /product/
product_show ANY /product/{id}/show
product_new ANY /product/new
product_create POST /product/create
product_edit ANY /product/{id}/edit
product_update POST /product/{id}/update
product_delete POST /product/{id}/delete
Default Routing in Symfony2
But would it not be prettier when the only routing entry you needed (per bundle) was this one?
# app/config/routing.yml
demo_bundle:
resource: "@AcmeDemoBundle"
type: default
prefix: /
And your code would NOT contain “@Route” and “@Template” annotations and look like:
/**
* Product Controller
*/
class ProductController extends Controller
{
/**
* Lists all Product entities.
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AcmeDemoBundle:Product')->findAll();
return array('entities' => $entities);
}
// ...
}
Your routes could look like this:
maurits@pc:~/project$ app/console router:debug
[router] Current routes
Name Method Pattern
... ... ...
acme_demo.product.index ANY /product/index.{_format}
acme_demo.product.show ANY /product/show/{id}.{_format}
acme_demo.product.new ANY /product/new.{_format}
acme_demo.product.edit ANY /product/edit/{id}.{_format}
acme_demo.product.delete ANY /product/delete/{id}.{_format}
To achieve this we needed to combine the “new” & “create” and “edit” & “update” actions and also remove
the “$request” argument from the “delete” action and replace it by a simple “$request = $this->getRequest();” call. So this code:
/**
* Displays a form to edit an existing Product entity.
*
* @Route("/{id}/edit", name="product_edit")
* @Template()
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AcmeDemoBundle:Product')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Product entity.');
}
$editForm = $this->createForm(new ProductType(), $entity);
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
/**
* Edits an existing Product entity.
*
* @Route("/{id}/update", name="product_update")
* @Method("POST")
* @Template("AcmeDemoBundle:Product:edit.html.twig")
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AcmeDemoBundle:Product')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Product entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createForm(new ProductType(), $entity);
$editForm->bind($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('product_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
has to be changed reduced into this:
/**
* Edits an existing Product entity.
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AcmeDemoBundle:Product')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Product entity.');
}
$editForm = $this->createForm(new ProductType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$editForm->bind($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('edit', array('id' => $id)));
}
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
Relative Routing
As a bonus this bundle allows you to refer relatively to another route, so instead of writing in the view:
<!-- Acme/DemoBundle/Resources/views/Product/index.html.twig -->
<a href="{{ path('acme_demo.product.show', { 'id': entity.id }) }}">show</a>
You can simply write this:
<!-- Acme/DemoBundle/Resources/views/Product/index.html.twig -->
<a href="{{ path('show', { 'id': entity.id }) }}">show</a>
Or instead of writing this in the controller:
$this->generateUrl('acme_demo.product.show', array('id' => $id))
You can simply write this:
$this->generateUrl('show', array('id' => $id))
Since routes are now expected to be “{bundle}.{controller}.{action}” format and the current route is “acme_demo.product.index” the undefined route “show” can be automatically matched to “acme_demo.product.show”. Apart from enforcing consistency this also allows for greater reuse of (parts of) code.
Get the bundle
Now quickly go grab a copy of the LswDefaultRoutingBundle and enjoy its benefits!
Symfony2 CRUD generator
I have ran into a real hidden gem. A YouTube user called “goyocode” has put an excellent series on using the CRUD generator in Symfony2 online. The links are below:
0. How to Generate an Entity in Symfony2 (11:41)
http://www.youtube.com/watch?v=0SE09AlJSEI
1. How to Generate a Repository in Symfony2 (1:20)
http://www.youtube.com/watch?v=asC9LL4cHrs
2. How to Generate CRUD for an Entity in Symfony2 (4:36)
http://www.youtube.com/watch?v=Jqp781knyPM
3. How to Install and Configure the Sonata Admin Bundle (11:19)
http://www.youtube.com/watch?v=_ZGRs4Rd94A
4. How to Create a ManyToMany Relationship with Doctrine2 & Symfony2 (27:35)
http://www.youtube.com/watch?v=akV4D7cq4UQ
5. Hack to Update a ManyToMany Relationship Through the Inverse Side in Doctrine2 (4:00)
http://www.youtube.com/watch?v=kPrgoe3Jrjw
It clearly explains the process of generating applications using the (Doctrine) CRUD generator in video’s 0,1 and 2. In video 3 the (Sonata) admin generator is explained. Video 4 and 5 explain the more advanced entity relationships “ManyToMany” and “inversed ManyToMany”.
Automatic updates in Symfony2
With a lot of pride we present our 7th Symfony2 bundle: LswAutomaticUpdateBundle. You could say we are on a role here, since all these bundles were published in the past 3 months! We are very proud that LswGettextTranslationBundle seems to be installed a lot (588 installs so far) and that LswApiCallerBundle was top trending bundle this month on http://knpbundles.com.

Automatic Update Bundle
So, what is new? Well, would’nt it be cool to have a WordPress-style automatic update button? That’s exactly what we deliver with LswAutomaticUpdateBundle! Whether or not this desirable can be argued about, but if you are after fast and consistent deployments, this might work for you. You get an extra icon in the Web Debug Toolbar indicating how long ago you last ran the Composer ‘update’ command. By clicking the icon you get to a panel where you can enter the password to actually execute the upgrade. Before the upgrade is executed the dry-run is executed. Only if all commands succeed, the upgrade button is shown.
Features
The bundle does some cool tricks, such as:
- Showing app/console and composer.phar output in color, thanks to ANSI to HTML support.
- Showing days not updated to remind you to keep your software up-to-date.
- Listing all requires and installed versions of the packages with their descriptions.
- Identifying unstable (dev) packages to encourage you to run stable versions
It also has some password based security, so that it can only be invoked by authorized people.
Pros and Cons
Maybe system administrators could see this bundle as a stability threat, because it enables quick updating of the code. Also, from a security point of view one could argue that this bundle is not desirable, since the use of ‘system()’ calls from PHP to execute shell commands is frowned upon.
On the other hand the bundle encourages frequent updates and use of versioned packages which should enhance security. Also, because this is a single click upgrade, upgrades should not fail because somebody forgot to type a command or makes a mistake in a command.
Installation
As always, you can find the bundle on Github and Packagist. It supports installation using Composer as described in the README.

