Tuesday 21 April 2015

Propel 2 and Symfony 2.6

Have you ever tried installing Propel 2 with Symfony 2.6 and wondered what the hell is wrong with my machine OR with my code. I am being particular about versions as I am not a full fledged Web developer.

History:
A friend of mine was playing with Symfony and came across Propel (ORM) and after spending some time, he called me to help him in configuring same. It was not as easy as we thought it would be. Here are our findings:

(NOTE : This post is all about my personal experience and these are my viewpoints)

a) Propel2 Documentation on official Symfony site is not up to date, it still shows some old configuration to install propel.

Official Documentation link :

It says use
{
    "require": {
        // ...
        "propel/propel-bundle": "1.2.*"
    }
}
in composer json file (Note: You should change propel version required as per symfony version you are using)

However It never worked for us, It could not download bundle along with it. After spending sometime searching for this (more appropriately struggling for sometime) , We came across some blog post (Do not remember link now) which suggested to try :


"require" : {
                "propel/propel": "~2.0@dev",
                "propel/propel-bundle": "~2.0@dev"
                }

in composer.json and to our surprise it worked for us, No more Bundle Not found error. 

Now Next Step was  not that difficult, we missed entry of Propel Bundle in AppKernel (infact many people does same). Simply Add 

new Propel\PropelBundle\PropelBundle(),

in $bundles array in app/AppKernel.php

Now it should work like charm, So we followed this link and tried to setup DB connection so we can start work happily.

But wait, life is not that simple. It says "dbal is unrecognised under propel". When googled this error, every second page was talking about some multi connections in propel. But we did not have any clue, we wanted only single connection.

As we know, patience always pays. Finally we found propel_link , however no where was mentioned about symfony integration, this is what we tried in our config,yml file:

#Propel ORM configurations
propel:
    database:
        connections:
            con1:
                adapter:   "%database_driver%"
                user:     "%database_user%"
                password: "%database_password%"
                dsn:      "%database_driver%:host=%database_host%;user=root;dbname=%database_name%;password=mysql;charset=%db_charset%"
    runtime:
        defaultConnection: con1
        connections:
            - con1
    generator:
        defaultConnection: con1
        connections:
           - con1

We had to give name to connection (con1 in our case) and had to mention that it is default connection. Finally our first command 

php app/console propel:database:create

executed and database was created.

And this is not good ending of story. My friend had existing database so he wanted to generate xml file from existing tables. So we read propel_existing_db and as given we tried running command :

php app/console propel:database:reverse "mysql:host=localhost;dbname=db;user=root;password=pwd"

and it never worked (probably only for us , thrown some error)

Before quitting, we simply tried to write connection name (like our soul felt to do so) which we gave in config.yml (con1), So tried 
php app/console propel:database:reverse con1


And finally it worked. With default configuration it created a folder named "generated-reverse-database" and a file "schema.xml" inside it (Ofcourse you can rename these by providing parameters to above command). Run

php app/console propel:database:reverse --help

and you will get to know all possible inout parameters.

So we were happy here and thought to generate model classes so that we can start work. We followed propel_build and ran following command :

php app/console propel:model:build 


and we encountered this exception :
No schema files were found (matching your schema fileset definition)
And after google sometime we reached this link propel_issue_schema and following it , we moved our schema.xml to Bundle/Resources/config/schema.xml

Now after running same build command :

Following exception came :

Please define a `package` attribute or a `namespace` attribute for schema `schema.xml`



Here we felt propel is guiding us with proper message in exception, so we did as it asked, added package name in <database> tag so that it applies to all tables as per documentation.

After adding package name, we ran again build command :

php app/console propel:model:build 

But to our surprise it started ignoring our schema file and thrown error :


No schema files were found (matching your schema fileset definition)

Now we could not understand what is exactly causing this, no much clue on internet even. If we remove package attribute from schema file it says "please define package or namespace", if we add package attribute, it started ignoring schema file. One thing was sure that it is able to read schema file from Bundle but second time it was expecting it somewhere else.


After digging into codebase via trace of exception, we realised it is looking for schema file inside cache directory of app folder. 

app/cache/dev/propel/schema_file_name.xml

(here dev is environment)

Now final solution we found was move schema.xml file to propel directory in env(dev/prod/test) inside cache.

And after this we were able to generate model classes with
php app/console propel:model:build 

If you still get error, make sure schema file is only at one position, i.e in your cache directory. Delete from your Resource directory in your bundle.

(One more weird solution we found to above problem, if you do not want to move schema file inside cache yourself, run generate schema command once and then move generated schema to Bundle/Resources/config and then run generate reverse schema command again, propel will automatically create a file name BundleName-schema.xml inside cache directory and you can run build model command -

php app/console propel:database:reverse con1

Now move generated schema.xml to Bundle/Resources/config/
 (Do not forget to add package/namespace attribute) and run

php app/console propel:database:reverse con1

again, propel will generate one file named BundleName-schema.xml in propel directory in cache. Do not forget to delete schema.xml file present in your Bundle/Resources/config

And finally,
php app/console propel:model:build 

Worked but with new welcoming exception :

  Invalid database name: no configured connection named `default`.  

It did not consume much time of ours, we tried replacing name which was default with connection name we had given in our config file under propel (in our case it was con1).

Finally it generated models as expected in given package attribute in file.

Now before using these generated models you need to run following command:
composer dump-autoload -o

P.S This might be very simply configuration to do,it is just some blockers we faced and thought to share, might help someone.