Distributing your project with symfony embedded

With symfony 1.0, one of the nice features was the freeze option, which allowed you to package the symfony libraries inside your project quite easily. This was very useful, for instance when deploying your project on a server where you couldn't install symfony. With symfony 1.1, it is apparently not advised anymore to use the freeze option (even though it is still available). So how should this be done then? Let's have a look...

I was a bit surprised earlier that freezing your project was not really advised anymore, it was the way I was used to working with my symfony 1.0 projects. However, with symfony 1.1 and some pointers I have found the new way of doing things to be very pleasant. So let me share it with you.

There are several reasons for embedding symfony inside your project. On your development environment, a reason can be to easily enable symfony 1.0 and 1.1 projects to be developed side by side. On your production server, it can be because you have no control over centrally installed libraries. But moreover because the right setup can ensure you always have the latest version. Let me elaborate on how I do this.

First of all, my central installation of symfony. It is a complete checkout of the symfony svn repository, which means I have the symfony 1.0, 1.1 and even 1.2 branch locally checked out for usage. However, I hardly use these. I only use them to create a new project. After that, it's all up to Subversion.

Creating a new project

When I create a new project, I use the centrally installed symfony checkout:

/path/to/symfony/repo/branches/1.1/bin/symfony generate:project newproject

This will create my new project in the current directory. This is just the project skeleton, and it is still using the symfony that can be found in /path/to/symfony/repo/branches/1.1

But first... Subversion

My initial new project needs to be put into Subversion first though. I import my new project and create a fresh checkout to work with. This means I can start using some nice advanced features of Subversion for embedding symfony into my project.

The vendor directory

The location for our symfony installation will eventually be lib/vendor/symfony in our project. For this to happen, the vendor/ directory needs to be created and added to Subversion. So I do:

mkdir lib/vendor
svn add lib/vendor
svn commit lib/vendor -m "added vendor directory"

Now, my vendor directory is ready for adding symfony.

svn:externals

It is of course possible now to put a copy of symfony in the lib/vendor/symfony directory. And this works fine if you want it. The downside of this approach is that any symfony upgrade needs to be done manually, which can be a pain. 

There are also strategies which keep a copy of the libraries inside the repository by using "vendor branches". This is an option as well, yet it still keeps the library code locally where there should be no need for such a thing.

Instead, in my setup, I use an svn:externals property to link the lib/vendor/symfony directory directly to the symfony repository. The advantage with this is that every time I do an svn up, I also get updates from the symfony repository, which may contain fixes for bugs that I could encounter. So, let's set up this external link in our project repository. 

svn propedit svn:externals lib/vendor

This opens a new editor window of my favorite editor for such tasks (in my case vim, could be different for you). In this editor, I add a line:

symfony http://svn.symfony-project.com/branches/1.1

What this line says is that a directory named symfony [inside the lib/vendor directory, as specified in the svn propedit command above] needs to contain the contents of the 1.1 branch out of the symfony svn repository. In my case, I am using the branch, but if you want more stability, you could link to a release tag, for instance the current 1.1.4 release tag.This will give you the stability of a release, but not the fixes of recent commits. However, when a new release comes out, you can always simply use the propedit command again to switch to the next tag.

Once I've created the svn:externals link to the external repository, I can simply do:

svn up lib/vendor

To get the latest version of symfony in my project. Do not forget to commit lib/vendor to get your svn:externals change propagated in your subversion repository.

Switch to your new checkout

This is all nice, but symfony is at this point still using the symfony installation I used to create the project. I need to point my project to it's internal symfony checkout. Luckily, with symfony 1.1, this is very easy as it requires only a single change. This change needs to be made in our project configuration, which can be found in config/ProjectConfiguration.class.php. In this file, there is a require line that currently contains the hardcoded path to the location of the symfony installation that you used to create this project. We will need to change this to a relative location inside our project:

require_once dirname(__FILE__) . '/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';

I am using a relative path to the ProjectConfiguration.class.php file here. I could hardcode this path to our project installation of symfony, however, there is a good chance that the server path to your project will not be the same on your test, staging or production machines. Therefore, making the path relative will ensure that your project runs on any of these machines without altering the configuration file.

The default styles and javascripts

Now there is one more thing left. Your default assets. So far I have not created my virtualhost configuration yet, but I need to ensure that this works. I could create a symlink in the web/ directory to lib/vendor/symfony/data/web/sf but those don't work well with Subversion (or other platforms). Best is to use the Alias option in your virtualhost configuration. Instead of having this point to my centralized symfony installation (as I used to do), I can now simply point it to the symfony in my project:

Alias /sf /var/www/mynewproject/lib/vendor/symfony/data/web/sf

And we're done. The only thing you need to do when you deploy this to another server (and this should only happen once per server) is that the last step, the virtualhost configuration, is done for that specific server setup. Once that is done, you're set.

As with many of symfony's features, this process is aimed at not duplicating the tasks you need to execute in your project. You only set this up once (in your development environment), and once that is done, you can deploy to as many systems as you want without having to do the same steps all over again. 


Add comment

Comments

gravatar chris: we do nearly like you except that we also create an svn:externals for the sf dir in our web directory (so that we do not need to modify the vhost config on our servers)
October 10, 2008
gravatar left: Hi Chris,

That is actually a good idea, I never thought of that. That solves the manual server configuration issue completely. Excellent idea, thanks.
October 10, 2008
gravatar Vid Luther: Just a quick clarification question.

Now, that you're using SVN externals and not using symfony freeze etc. Do you tag your development branch when it's "ready" for deployment, and then do an svn export of the tag in your production environment? Or do you still use symfony's tools to push to production?

Otherwise very informative article, I'll be deploying a symfony 1.1 project in the next week, and I'll use the methods here to setup the dev/stage areas so I can test things, and then deploy onto a server where I probably won't get root :)
October 10, 2008
gravatar left: Hi Vid,

Deployment is a different topic I guess (which I wrote about before), but let me clarify my approach on that:

Once I have a new version ready for deployment, I tag it in subversion. I do an export of the tagged version in a temporary directory, from which I then use ./symfony project:deploy to deploy to the server. So yes, I still use symfony's built-in deployment features, and actually in 1.2 or 1.3 we will get a more improved version of the deployment system, so there is absolutely no reason to move away from that :)
October 10, 2008
gravatar tom: you write that using "freeze" with symfony 1.1 ist not "advised" anymore.. Where did you get this advise from? In the current 1.1 documentation the freeze command is still described..

i used "freeze" a lot to deploy my projects on shard hosting servers.. there i cant use the method u describe.... thats why i would like to know, where you read/heard, that freeze should not be used with 1.1

thx..
October 10, 2008
gravatar Vid Luther: Thanks Stefan,
I'm curious what you feel are the advantages of the symfony deploy method, vs an svn export of the tag on the production server? Is it basically not having to worry about the svn server not having svn on it?

As I await your response, I'm googling symfony project:deploy
October 10, 2008
gravatar left: Tom: I was told that by Fabien, I think it was during our DPC tutorial.

Vid: I prefer to push new stuff instead of pulling it. I don't want my .svn directories to be "polluting" my production environment (so I want an export). But with an export, I need to move away my old version and put the new version in place. This may be a problem with uploaded files for instance. Too much to think of.

When using the project:deploy, only the changed files are pushed to the new server, and uploaded files stay where they are. There are no unnecessary files such as .svn stuff in there. It's less actions to accomplish the same thing. This also means less points where something might go wrong :)

You might find http://www.leftontheweb.com/message/Deployment_as_it_should_be interesting.
October 10, 2008
gravatar left: Oh and Tom, you can use the above described method on any shared hosting account as well. Because the svn export (which pulls the symfony into your lib/vendor directory) is in my case done on my local machine, before I project:deploy to the server. In the end, you'll end up with a similar setup as freeze.
October 10, 2008
gravatar Phil Moorhouse: Have you managed to do this with symfony 1.0.x ?

I attempted to do the same with
http://svn.symfony-project.com/tags/RELEASE_1_0_18/

but once I've modified the config.php to point at the correct directories:
$sf_symfony_lib_dir = dirname(__FILE__).'/../lib/vendor/symfony_1_0/lib';
$sf_symfony_data_dir = dirname(__FILE__).'/../lib/vendor/symfony_1_0/data';

I get a fatal error relating to /test/bootstrap/unit.php attempting to redeclare sfException - I guess the autoloader is including all the test files because it's under /lib.

Is there a way to include the symfony libs without the test dirs?

October 10, 2008
gravatar left: Phil,

I am not sure how easy it is. I've always used freeze with 1.0, and it was not until I started working with 1.1 that I found out about this new method. It is highly likely that for 1.0 there are several dependencies internally that makes this approach for 1.0 projects a problem, but I haven't tried it so I can't really tell you anything about it. I only know that in 1.1, there is only the dependency on the ProjectConfiguration, which makes it easier to use this approach.
October 10, 2008
gravatar Sherif: Great post, however I would not recommend this strategy if you want to host multiple Symfony sites on the same server - you will end up with quite a very large code-base (one Symfony instance per app). This is great but, for distributing your symfony apps.

If you are looking at hosting multiple apps on the same server, you are better of sharing the same Symfony libs for each version of Symfony - Here is how to do it: http://symfonynerds.com/blog/?p=123

Agree with your comment about freezing - I like that idea.. not sure really why it was taken out but..
October 10, 2008
gravatar ken: I also use subversion when managing/deploying my application.

cd project
svn propedit svn:ignore .*
cd log
svn propedit svn:ignore *
cd ../cache
svn propedit svn:ignore *
cd ../plugins
svn propedit svn:ignore .*

plugins as external
web/sf as external

i also make sure that i have a tagged copy of symfony in our repositiory plus the plugins

make sure also to ignore the om and map folders of plugins so that when you do commits, the repository will not be updated, just override them in lib dir

create also a template of config/config.php
cp config.php config.php.sample
svn propedit svn:ignore config.php

this way no freeze is needed. all you need to do is copy config.php.sample and modify the paths
October 21, 2008
gravatar Mark Quezada: I use pretty much the same approach, but I simply make a symlink from "/sf" to "../../lib/vendor/symfony/data/web/sf"

If you're on a unix box it makes it a whole lot easier and you don't have to have to svn:external links pointing to essentially the same thing.

Phil: I wrote an article a while back about using this approach on symfony 1.0: http://blog.mirthlab.com/2007/12/15/setting-up-a-symfony-project-on-media-temples-grid-service-part-1/

Look under "setting up symfony."

Also, I frequently reference this article which has several good tips on this: http://spindrop.us/2007/04/17/tips-for-symfony-and-subversion/

Hope that helps.
October 22, 2008
gravatar Open: Good idea, thank you.

Open
October 26, 2008
gravatar Colnector: svn:externals is the most flexible way to work since you can be just as updated as you like. I recommend to always compare the Symfony lib changes before updating your site’s webserver.
December 25, 2008

Php5_zce_logo

not tested in IE


Upcoming events

I will be speaking 08-10-2010: Symfony Day Cologne 2010
I will be speaking 09-10-2010: Symfony workshop

Tags

1337 2008 2010 4developers access modifiers accessibility AdaLovelaceDay09 advent agavi agile amsterdam apache apple article articles atk atkMetaNode audioscrobbler azure backwards compatibility barcelona bbc bbq beatstad belgium best practices bittorrent boards of canada book books bughuntday caching cake cal evans career cat cerf certificate cfp clear cms cologne common sense communities community conference conferences continuous integration contribute crisis css custom datetime DbFinderPlugin decorator decorators deployment devdays development directoryindex documentation download dpc dpc09 dpc10 DPC2008 dreamhost dv7 eclipse ed efficiency enterprise errors event events expertise ezcomponents facebook flickr framework frameworks freelance freeze frontend fun games germany getting real google googletalk graceful degradation hack hackers hidden gem hiphop howto hp html http ibuildings icann ide idm imovie indy ingewikkeld internet IPC ipc ipc08 javascript job jobeet john peel joomla kubuntu left on the web lighttpd lime linux live london loudblog m2ts mac malware mambo marjolein mediterra meeting meme meta methodology microsoft movie music mysql namespace namespaces netbeans netherlands nllgg odmarco open source opinion ORM osx paradiso pavilion pear performance personal pfc10 pfcongres pfcongrez photo php phpabstract phpazure phpBB phpbb phpbelgium phpbenelux phpbnl10 phpgg phpitalia phpnw phpnw08 phptek phptek09 phpuk2009 phpUnderControl phpunit php|architect php|tek podcast politics portability postcrossing presentation presentations private projects protected public qa recruiting refactoring review rewrite ruby on rails schedule scifi script security seven things sfdaycgn simplexml slides smfony software sogeti solar sound standard standards star trek static steer strings subversion symfony Symfony2 symfonycamp symfonyday symfonyUnderControlPlugin talk talks technology techportal tek09 telecommuting terratec terrorism testfest testing textpattern tips tld tomas training twig uncon unet usability usergroup validation vhost video vinyl virus warp weblogging wiki windows winphp women work workshop world world of warcraft wpi writing xml xpath xsd yara year youtube ZCE zemanta zend zend framework zend server zend studio Zend_Form
© 2004 - 2010 Stefan Koopmanschap + Powered by Symfony, photos powered by Flickr, links powered by Delicious, Shanghai smilies by Iconbuffet. Feeds: rss / atom. Left on the Web v4.4.0.1