I am currently developing a php-application for a charity organization and I am now in the stage of defining the deployment practices.
Our application is using both Zend
Benjamin Eberlei posted a blog a few weeks ago titled Trying a Two Step PEAR/PHAR approach to develop and deploy. He describes is a very interesting and elegant procedure for deploying a PHP application.
I'd start by making the application root of the various servers an SVN working copy. You can add in mod_rewrite (or IIRF ASAPI filters for IIS) rules to ensure people can't address your .svn directories directly.
Then, updating to the latest source can be as simple as an SVN update. For your database update needs, I'd maintain the database modification scripts also in SVN. You'll likely need to wrap the SVN update in a batch/shell script in order to perform the database updates after the scripts are downloaded.
For change management on the live servers, I'd also have their working copies not of trunk, but a release branch. You can merge trunk into the release branch when you are ready for a release. This will allow you to test the deploy and make sure it's solid before performing it on the live servers. It also has the nice side-effect of giving you a nice replica of the site-release versions in case you need to track down issues post-launch.
Lastly, depending on the intensity and timing of these updates, you may also want to have your update script flip an "under maintenance" switch so that users are temporarily met with a proper message rather than a broken site.
Perhaps sometimes a simpler approach works best. If you keep stable releases simply tagged within the svn repo then you can just write a batch / bash script to download the newest revision whilst backing up to old with no user intervention - you can also run any scripts required in this way. Another alternative is writing a simple interface to this in PHP but it depends on how simple it needs to be.
You said that you have a claster. We're in the same position and we use ZF and Doctrine. This is how we solved the problem:
<?xml version="1.0" encoding="UTF-8"?>
<project name="yourprojectname" basedir=".">
<target name="deploy" depends="apply-deltas,update-app01,update-app02">
</target>
<target name="update-app01">
<sshexec host="app01"
username="yourusername"
password="yourpassword"
trust="true"
command="cd path/to/root/directory &&
svn update &&
php cmd/clear_cache.php
"/>
</target>
<target name="update-app02">
<sshexec host="app02"
username="yourusername"
password="yourpassword"
trust="true"
command="cd path/to/root/directory &&
svn update &&
php cmd/clear_cache.php
"/>
</target>
<target name="apply-deltas" depends="liquibase-prepare">
<updateDatabase
changeLogFile="${db.changelog.file}"
driver="${database.driver}"
url="${database.url}"
username="${database.username}"
password="${database.password}"
promptOnNonLocalDatabase="${prompt.user.if.not.local.database}"
dropFirst="false"
classpathref="classpath" >
<changeLogProperty name="table.name" value="ant_param_table"/>
</updateDatabase>
</target>
<target name="liquibase-prepare">
<path id="classpath">
<fileset dir="${basedir}/libNoPackage">
<include name="**/*.jar" />
</fileset>
</path>
<taskdef resource="liquibasetasks.properties">
<classpath refid="classpath"/>
</taskdef>
</target>
</project>
This is far from ideal but it works fine for us. Hope that helps.
Links:
Apache Ant
LiquiBase
If you have some questions please let me know so I can update the answer.t
Either way, I would manage your builds with phing or something similar. Let it run your tests, generate docs, build and publish your package/tarball.
As for distribution, you could run your own PEAR server. Rationale here is you said you want users to pull updates, you have both Windows and Linux users, and you want to handle dependencies for them. PEAR should be able to handle all that with one command.
That said, I would go with the simplest thing that works and suits your users. That could just be a tarball available via HTTP and a small PHP upgrade script (or a phing target.)
Definitely provide a simple way to rollback to a previous version. With code/configuration you can just keep a copy. With DB, use migrations (which it sounds like you're doing already.)
I've used subversion as a deployment tool to great effect.
Use svn update on all your production servers, or use phing. (Or use phing to svn update, even.)
Makes rollbacks and backups a snap. Just remember to remove access to any .svn directories.