Archive for November, 2008
phpVMS 1.1.400 released, lessons learned
I put out the update for 1.1.400 (version bump, went from 1.0 to 1.1 because of “major” features), then the 400 being the revision number from SVN. So far no problems, my main concern were the tons of database changes, including the removal of foreign keys, which made me a bit nervous, since I guess different versions react differently.
Instead of doing scratch installs, and then doing an update (time consuming), I wrote a quick SQL file, and another bash script which would automatically insert the older 1.0 database (basically running the install.sql), and then run the update.sql, and report any errors which are thrown:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/bin/bash
# MySQL Installer and Update Check
# Nabeel Shahzad <http://www.nsslive.net>
DBUSER=""
DBPASS=""
DBNAME=""
DBSERVER=""
INSTALLFILE='install.sql'
UPDATEFILE='update.sql'
mysql -u uname dbname -e "show tables" | grep -v Tables_in | grep -v "+" | \
gawk '{print "drop table " $1 ";"}' | mysql -u uname dbname
mysql -u $DBUSER -p $DBPASS -h $DBSERVER $DBNAME < $INSTALLFILE
clear
mysql -u $DBUSER -p $DBPASS -h $DBSERVER $DBNAME < $UPDATEFILE |
The line to drop all the tables was from this page here (thanks!). My install.sql can also include the SQL inserts for default values (I will post the code for my installer soon, since it’ll just read any .sql file), but what I will do is create a backup of an existing DB with all my data, and run the update against that using this script.
Pretty basic, but really handy to just viewing errors.
Subversion as build tool
I use Subversion to manage all of my projects, since it’s an easy tool to setup, and manage repositories with. I use the SmartSVN client to manage all my check-ins and checkouts. But something I have with phpVMS to to automatically create builds with the proper version numbers. I have an update script, which will make database changes, as well as update the version numbers. I base the version number off of the Subversion revision number, which is incremented every time code is checked in. The steps I take for a build are:
- Check the current revision number
- Update the update script to the next revision number
- Commit the check in
- Export the SVN code
- Create a tar file with the full install, with the build number
- Create another update install, with the local config removed, with the build number
- Move these files to the download area
- Move the exported code into my test area to keep it updated.
It’s annoying to do with each check in, and whenever there’s an update, I have to do it again. This is the perfect flow to create a script to handle. So I created a bash script, which can be called through a cron-job, on the command-line, or as a post-commit hook in the repository. So here’s the script (read through the comments!)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#!/bin/bash
# Variables
REPOS="http://svn.devjavu.com/phpvms/trunk"
EXPORT="/path/to/temp/export"
MOVETO="/path/to/test/directory"
DOWNLOADSPATH="/path/to/downloads/directory"
# Revision Number will be tacked on the end
VERSION="1.0."
# Cleanup our export directory
rm -drf $EXPORT
# Export and get the revision number
echo "Exporting from SVN"
REVISION=`svn export --force $REPOS $EXPORT | grep -i -o -e "revision.*[0-9]"`
REVISION=${REVISION:9}
echo "Retrived revision $REVISION, adding to update file"
# Add the version number into the update script
# Replace the <<UPDATE>> with the version + revision number
sed -i "s/<<UPDATE>>/$VERSION$REVISION/g" $EXPORT/install/update.php
# Create the full install
echo "Creating full install file"
rm -f $EXPORT.$REVISION.full.tgz
tar czf "$EXPORT.$REVISION.full.tgz" $EXPORT
# Create the update
# Remove the local.config.php file
echo "Creating the update"
rm -f $EXPORT.$REVISION.update.tgz
rm -f $EXPORT/core/local.config.php
tar czf "$EXPORT.$REVISION.update.tgz" $EXPORT
# Clean up the destination directory
# But I don't want to since my config file is there
#if [ -d $MOVETO ]; then
# rm -drf $MOVETO
#fi
#mkdir $MOVETO
echo "Moving to test area"
# Now move it to our test area
cp -Rf $EXPORT/* $MOVETO
# Move our tars to our download area
echo "Moving downloads"
mv -f $EXPORT.$REVISION* $DOWNLOADSPATH
echo "Done!" |
So I do an export of the SVN cache, and then run “grep” to get the revision number. After that, it’s just basic directory and file manipulation. It’s also helpful if you need to compile some code.
In my update.php, I placed the following:
|
1 |
define('UPDATE_VERSION', '<<UPDATE>>'); |
Which then gets replaced by the version number with this line:
|
1 |
sed -i "s/<<UPDATE>>/$VERSION$REVISION/g" $EXPORT/install/update.php |
If you have multiple files, it’s just a matter of copy/pasting that line to include your files with the update. Enjoy!
Keys to an excellent web-app: API
During the development on phpVMS, I found I was splitting my time as 95% programming new features, and 5% debugging. I attribute this to something, which is often over-looked when creating a web-application, an API – "Application Programming Interface". When you hear the word(s), you probably are thinking more towards actual applications, something running on your desktop, or maybe in Windows or Linux. But an API serves well in web applications also. While frameworks, like my own Codon, or Symfony, Zend, etc all have APIs, it serves well to plan and write out your own API for your application.
To start, what’s an API? It’s a common interface to do things. For example, database operations, an API serves well to managing all your queries from a central place. But what’s the point? Look at my new code to bugs ratio. An API speeds up development time, allowing you to concentrate on logic, rather than fumbling with getting the basics working. Frameworks serve the same purpose, but a framework is only as good as the API backing it.
Designing your data model
I first designed my database for phpVMS. I knew I needed a table to contain all of the pilot reports, “pireps” for short. So there are a few steps to designing a good API:
- Adding a PIREP
- Removing a PIREP
- Editing a PIREP
- Changing the status of a PIREP
- Retrieving PIREPs
- Retrieve PIREPs on a certain date
- Retrieve PIREPs for a certain pilot
- etc
Instead of writing them in-line, while I’m writing the front-end code, I like to work backwards, starting with the database functions I would need., working my way to the controller, than then finally the HTML template. This works well combined with a feature of PHP 5 – static classes.
|
1 2 3 4 5 6 7 8 |
class PIREPData
{
public static function GetAllPIREPS()
{
$sql = "...";
return db_results($sql);
}
} |
Now with the above code, in any piece of code, I can do:
|
1 2 3 4 5 |
$allpireps = PIREPData::GetAllPIREPS();
foreach($allpireps as $pirep)
{
echo ...
} |
And have all of my PIREPS, and I can cleanly display it. If I need to do it anywhere else, I don’t need to copy/paste SQL code, which I may have to debug or change later on.
Being Consistent
This is the next step to designing a good API. Consistency means:
- Keep return data uniform
- Keep variable names consistent
- Make sure you use it!
Returning uniform datasets:
This seems a little odd, but I’ve seen code where one API function will return HTML, another will return just a dataset. I keep as a rule to only return datasets, and then decide what I want to do with that dataset. For instance, I keep track of “flights” through an interface. I use the same API call to build an HTML table, and also the same API call to then build an XML result-set from that data to use elsewhere.
Keep variable names consistent
This one bugs me when I see it. For instance, I use the variable name $pilotid. I only use $pilotid. Not $p_id, $pid, $pilot_id, or the worst I’ve seen, $p (wth is $p??).
Make sure you use it!
I’ve often seen a good API, but no one bothers using it, instead re-writing the code to either it’s in the format that they (and only they!) want, even though the API function can easily be processed to provide the functionality, or just plain-out re-writing code. Always drill it into your head and programming to look before you code! Spending 15 minutes to analyze an existing data model can save a lot of time and head-ache in the long run.
phpVMS
Update is coming soon! I think people will be surprised on the few things that are included in this update. A ton of code optimizations, and other small (some big!) requests people wanted have also been included.
Codon is also coming up on an update soon, though I’ve been trying to get a good site together for it. The core code I haven’t yet touched because of phpVMS and work, there are a few bugs that I need to fix. The good news is, a few commercial places are interested. May be enough for me to start working on it again.
nsslive site
Finally getting the nsslive site live!