Object Relational Mapping with Propel

Propel is a stand-alone Object-Relational Mapping (ORM) library, which we'll be using rather than rolling our own database models. It automatically creates a set of full-featured model classes from a database (or the other way around), saving you a lot of time and effort. Setup is not fun, but once you're there, the amount of work you'll save is quite impressive.

Step One: Install Composer

Linux has a long history of excellent package managers that handle installing software components and keeping track of them. This contrasts with the Windows approach where every program has a stand-alone, monolithic installer. Package management is a great feature for development in particular, where you need to manage a number of different libraries (called dependencies) as your project grows. Modern web languages and environments have all adopted the package management approach, from gems in ruby, pip in python, NPM in node.js, and so on. In PHP, there are a few options, one of which is the Symfony project's composer.

On Windows

Composer has an easy-to-use windows installer. Download it here and run it. It will ask you what PHP to use - you should select the one in your XAMPP installation. It also updates your PATH variable (PATH determines where the command line looks for programs that you attempt to run). After installation, it should run anywhere:

On Linux

A local install in your project directory is the easiest route. Navigate to the project directory and follow the instructions from the Download Page:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

The composer.phar file in the directory can now be run locally using php.

etomai@lamp-6312-vm:~/myproject$ ls -la
total 2128
drwxr-xr-x 2 etomai etomai    4096 Mar 15 14:52 .
drwxr-xr-x 6 etomai etomai    4096 Mar 15 14:52 ..
-rwxr-xr-x 1 etomai etomai 1861877 Mar 15 14:52 composer.phar
etomai@lamp-6312-vm:~/myproject$ php composer.phar --version
Composer version 1.6.3 2018-01-31 16:28:17

Step Two: Install Propel

Web frameworks tend to "install" by adding a sub-directory full of files to your project. Composer's job is to manage all those sub-directories. It's behavior should be the same on all platforms. To add Propel:

  1. Create or go to the project directory
  2. Create a file named composer.json in that directory
  3. Specify in json what dependencies your project needs (propel in this case). You can use the nano editor on linux, or any text editor available. The contents of the file should look like this:
    {
        "require": {
            "propel/propel": "~2.0@dev"
        }
    }
  4. Run composer install (windows), or php composer.phar install (linux) in that directory. (screenshot from windows, but output is the same either way).

When composer is done, there will be a sub-directory called vendor in your project, where all the files from third-party dependencies go. You generally won't touch anything in there, just like we didn't edit the jquery.js file.

Building Your Models

For this example, I'm working with my basic person-address database addresses_basic_nofk.sql:

Generating the models is described in the Propel docs, but it's a little unclear. It says at the bottom of the page to just run propel init, which is mostly accurate, but omits a few things you have to do after that.

Verify PHP (Windows)

On windows, make sure that you can run the PHP script from your project directory. The composer installer on Windows adds php to your path, so you should be able to run it anywhere. On other platforms, php is likely already included in your path.

Run the Interactive Build Tool

When you installed propel, it included the script vendor/bin/propel. To run the auto build script, you run vendor\bin\propel.bat init (windows) or vendor/bin/propel init (linux) in the project directory. Most of the default options (the ones in []) are correct (just hit return), but pay attention to the ones that matter for the test db you are working with (which db type, database name, yes I have a database, store the generated models in the models directory).

The build process creates files that describe your database to Propel (propel.yml and schema.xml), which it then uses to create model classes. I put my model classes in the models directory, just to be neat. note that propel created a pair of models for each of my tables.

Now here's the part that's not really well explained in the Propel doc (it's further back up the page). PHP has a complicated autoloading system to manage large projects, and one way to access it is through composer. What we need to do here is make composer aware of our newly generated classes, so that it can add them to the autoload system.

Update your composer.json file by adding an additional section to tell composer where you put your generated models. If you didn't put them in the models sub-directory, specific where you did put them instead.

{
    "require": {
        "propel/propel": "~2.0@dev"
    },
    
    "autoload": {
      "classmap": [
        "models/"
      ]
    }
}

Then run composer dump-autoload (windows) or php composer.phar dump-autoload (linux), which updates a special file called vendor/autoload.php so that your PHP pages can conveniently include all the models you generated. Any time you make changes to your database and re-generate the models, you should run this again.

Do Something

Finally! That is the setup process for any project where you want to use Propel to generate your database models for you. Now we'll do a quick example on how to use those models. Considerably more detail is available in the Propel docs.

I'll leave you here with a simple example PHP page. If you put this code in a PHP file in your project directory, modify it for the db you are using (note that snake-case in the db is converted to camel-case in the models, so last_name becomes LastName), and link it from /var/www/html, the page will show the name of the third record (index 2).

// invoke autoload to get access to the propel generated models
require_once 'vendor/autoload.php';

// require the config file that propel init created with your db connection information
require_once 'generated-conf/config.php';

// now this script can access the database through the propel models!

// retreive a person by id and print their name
// note that the getters were generated based on the db col names first_name and last_name

$p = PeopleQuery::create()->findPk(2);
echo "<p>".$p->getLastName().", ".$p->getFirstName()."</p>";