Chapter 3. Getting Started With PHOCOA Tutorial - Building a Blog

PHOCOA has a very large set of technologies. Because it is based on Cocoa (Apple's development infrastructure), if you are a Cocoa programmer things will make a lot of sense to you. If you are not familar with Cocoa, there is a bit of a learning curve. But trust us, it's worth it. The power of PHOCOA will allow you to deliver robust web applications with minimal coding in record time.

Instead of starting off by explaining all of the concepts and technologies, we will first walk you through the steps to build a simple application (a blog) to show you how easy it is to write PHOCOA applications. You will be much more motivated to learn the concepts when you realize how much time PHOCOA can save you.

This chapter will walk you through the development of a simple blog application that shows off all of the basic concepts. We will explain each concept as simlpy as possible for the example.

3.1. Starting a New Project

PHOCOA comes with a shell script to help you manage common PHOCOA tasks. This script is aptly named phocoa.

Note

If you're not using a PEAR install of PHOCOA, the phocoa command won't be in your path. The phocoa command is located at phocoa/phing/phocoa. We recommend that you alias it to avoid having to type the entire path each time.

Let's use phocoa to create a new workspace for our blog project.

$ phocoa newProject
phing -f /Users/alanpinstein/dev/sandbox/phocoa/phocoa/phing/build.xml -Dusing.phocoa.make=true -Dphocoa.pwd=/Users/alanpinstein/dev/sandbox 
-Dphocoa.dir=/Users/alanpinstein/dev/sandbox/phocoa/phocoa -Dphocoa.project.name= -Dphocoa.project.dir= newproject
Buildfile: /Users/alanpinstein/dev/sandbox/phocoa/phocoa/phing/build.xml

phocoa > prepareGeneral:
     [echo] PHOCOA framework base dir at: /Users/alanpinstein/dev/sandbox/phocoa/phocoa

phocoa > newProject:
Enter the name of the new project: [] blog
     [echo] The container directory for your PHOCOA project will be used to place the log, runtime, and project directories. Please be careful!
Enter the path to the project container directory: [/Users/alanpinstein/dev/sandbox/blog] 
[realpathexpandhome] Resolved /Users/alanpinstein/dev/sandbox/blog to /Users/alanpinstein/dev/sandbox/blog
Enter the name of the server (ie dns name) that will host this application: [localhost] blog.phocoa.com
Enter the IP of the server that will host this application: [127.0.0.1] 10.0.1.201
Enter the PORT of the server that will host this application: [80] 8080
[phingcall] Calling Buildfile '/Users/alanpinstein/dev/sandbox/phocoa/phocoa/phing/build.xml' with target 'setupProjectContainer'

phocoa > setupProjectContainer:
     [echo] Creating project container directories and setting up permissions
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/log
    [chmod] Changed file mode on '/Users/alanpinstein/dev/sandbox/blog/log' to 777
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/runtime
    [chmod] Changed file mode on '/Users/alanpinstein/dev/sandbox/blog/runtime' to 777
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/runtime/smarty/templates_c
    [chmod] Changed file mode on '/Users/alanpinstein/dev/sandbox/blog/runtime/smarty/templates_c' to 777
     [echo] Creating project directory: /Users/alanpinstein/dev/sandbox/blog/blog
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/blog
     [echo] Copying PHOCOA templates...
     [copy] Copying 9 files to /Users/alanpinstein/dev/sandbox/blog/blog
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/blog/wwwroot/www
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/blog/modules
     [echo] Setting up configuration files...
     [copy] Copying 3 files to /Users/alanpinstein/dev/sandbox/blog/blog
[filter:ReplaceTokens] Replaced "##SERVER_IP##" with "10.0.1.201"
[filter:ReplaceTokens] Replaced "##SERVER_PORT##" with "8080"
[filter:ReplaceTokens] Replaced "##SERVER_NAME##" with "blog.phocoa.com"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_BASE_DIR##" with "/Users/alanpinstein/dev/sandbox/phocoa/phocoa"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_BASE_DIR##" with "/Users/alanpinstein/dev/sandbox/phocoa/phocoa"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_CONTAINER_DIR##" with "/Users/alanpinstein/dev/sandbox/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_CONTAINER_DIR##" with "/Users/alanpinstein/dev/sandbox/blog"
[filter:ReplaceTokens] No token defined for key "##PHOCOA_APP_DIRBASE_DIR##"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_BASE_DIR##" with "/Users/alanpinstein/dev/sandbox/phocoa/phocoa"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_CONTAINER_DIR##" with "/Users/alanpinstein/dev/sandbox/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_CONTAINER_DIR##" with "/Users/alanpinstein/dev/sandbox/blog"
[filter:ReplaceTokens] Replaced "##PHOCOA_APP_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/blog"
[phingcall] Calling Buildfile '/Users/alanpinstein/dev/sandbox/phocoa/phocoa/phing/build.xml' with target 'httpdconf'

phocoa > prepareGeneral:
     [echo] PHOCOA framework base dir at: /Users/alanpinstein/dev/sandbox/phocoa/phocoa

phocoa > prepareProject:
     [echo] 1
      [php] Evaluating PHP expression: $_ENV['_']
     [echo] PHOCOA project dir at: /Users/alanpinstein/dev/sandbox/blog/blog
[realpathexpandhome] Resolved /Users/alanpinstein/dev/sandbox/blog/blog/.. to /Users/alanpinstein/dev/sandbox/blog
     [echo] PHOCOA project container dir at: /Users/alanpinstein/dev/sandbox/blog
 [property] Loading /Users/alanpinstein/dev/sandbox/blog/blog/conf/build.properties
 [property] Unable to find property file: /Users/alanpinstein/dev/sandbox/blog/blog/conf/build.properties... skipped

phocoa > httpdconf:
     [echo] PHOCOA requires some httpd configurations to work its magic. You must either be able to edit httpd.conf, or have an apache with mod_rewrite enabled.
Select httpd configuration mode: 1=httpd.conf, 2=.htaccess [1] 1
     [echo] Make sure your httpd.conf file contains the line: Include /Users/alanpinstein/dev/sandbox/blog/blog/blog/conf/httpd.conf
Will this project use database access via Propel?(yes/no) [1] yes
[phingcall] Calling Buildfile '/Users/alanpinstein/dev/sandbox/phocoa/phocoa/phing/build.xml' with target 'addpropel'

phocoa > prepareGeneral:
     [echo] PHOCOA framework base dir at: /Users/alanpinstein/dev/sandbox/phocoa/phocoa

phocoa > prepareProject:
     [echo] 1
      [php] Evaluating PHP expression: $_ENV['_']
     [echo] PHOCOA project dir at: /Users/alanpinstein/dev/sandbox/blog/blog
[realpathexpandhome] Resolved /Users/alanpinstein/dev/sandbox/blog/blog/.. to /Users/alanpinstein/dev/sandbox/blog
     [echo] PHOCOA project container dir at: /Users/alanpinstein/dev/sandbox/blog
 [property] Loading /Users/alanpinstein/dev/sandbox/blog/blog/conf/build.properties
 [property] Unable to find property file: /Users/alanpinstein/dev/sandbox/blog/blog/conf/build.properties... skipped

phocoa > addpropel:
     [echo] Setting up PHOCOA project for Propel in dir: /Users/alanpinstein/dev/sandbox/blog/blog/propel-build
Select the path for executable: propel-gen:  /Users/Shared/src/propel-1.3.0beta2/generator/bin/propel-gen
[selectExecutable] Using propel-gen at /Users/Shared/src/propel-1.3.0beta2/generator/bin/propel-gen
    [mkdir] Created dir: /Users/alanpinstein/dev/sandbox/blog/blog/propel-build
Enter the database type:(pgsql,mysql,mssql,sqllite,ldap) pgsql
Enter the database name: blog
Enter the database username: blog
Enter the database password: 
Enter the database host: [localhost] 
[writeconffile] Writing conf file: /Users/alanpinstein/dev/sandbox/blog/blog/propel-build/build.properties.
     [echo] Building Propel... setup conf file, reverse engineer database, build db classes.
     [copy] Copying 1 file to /Users/alanpinstein/dev/sandbox/blog/blog/propel-build
[filter:ReplaceTokens] Replaced "##LOG_DIR##" with "/Users/alanpinstein/dev/sandbox/blog/log"
[filter:ReplaceTokens] Replaced "##PHOCOA_PROJECT_NAME##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_NAME##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_NAME##" with "blog"
[filter:ReplaceTokens] Replaced "##PROPEL_DATABASE##" with "pgsql"
[filter:ReplaceTokens] Replaced "##PROPEL_DATABASE##" with "pgsql"
[filter:ReplaceTokens] Replaced "##DB_NAME##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_USER##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_HOST##" with "localhost"
[filter:ReplaceTokens] Replaced "##DB_PASS##" with ""
[filter:ReplaceTokens] Replaced "##PROPEL_DATABASE##" with "pgsql"
[filter:ReplaceTokens] Replaced "##DB_HOST##" with "localhost"
[filter:ReplaceTokens] Replaced "##DB_NAME##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_USER##" with "blog"
[filter:ReplaceTokens] Replaced "##DB_PASS##" with ""
     [exec] Executing command: /Users/Shared/src/propel-1.3.0beta2/generator/bin/propel-gen /Users/alanpinstein/dev/sandbox/blog/blog/propel-build convert-props 2>&1
     [exec] Buildfile: /Users/Shared/src/propel-1.3.0beta2/generator/build.xml
     [exec] [resolvepath] Resolved /Users/alanpinstein/dev/sandbox/blog/blog/propel-build to /Users/alanpinstein/dev/sandbox/blog/blog/propel-build
     [exec] 
     [exec] BUILD FAILED
     [exec] Target 'convert-props' does not exist in this project.
     [exec] Total time: 0.1039 seconds
     [echo] Propel general setup complete.
     [echo] To complete propel integration, complete the following manual tasks:
     [echo] 1. Make sure that propel is available in your include_path. If not, edit webapp.conf and munge include_path.
     [echo] 2. Add define('PROPEL_CONF', APP_ROOT . '/conf/blog-conf.php'); to your webapp.conf.
     [echo] 3. Add Propel::init(PROPEL_CONF); to your WFWebApplicationDelegate's initialize() method.
     [echo] 4. Edit the propel/runtime/classes/propel/om/BaseObject.php BaseObject declaration to this: 'abstract class BaseObject extends WFObject'.
If your database already exists, we can generate a PHP interface to your database objects. Does your database already exist?(yes/no) [] no
     [echo] Skipping Propel code generation. You can always generate your classes with Propel in the future:
     [echo] /Users/Shared/src/propel-1.3.0beta2/generator/bin/propel-gen /Users/alanpinstein/dev/sandbox/blog/blog/propel-build main
     [echo] Done adding Propel support.
     [echo] New Project setup complete.

BUILD FINISHED

Total time: 36.6166 seconds

You should now have a directory blog containing your new PHOCOA application.

$ ls -l blog 
total 0
drwxr-xr-x   8 alanpins  showcase  272 Sep 11 14:20 blog
drwxrwxrwx   2 alanpins  showcase   68 Sep 11 14:20 log
drwxrwxrwx   3 alanpins  showcase  102 Sep 11 14:20 runtime

This directory contains your PHOCOA deployment structure. This directory is called the container directory because it contains your web application, including your PHOCOA application project. Typically, log and runtime (tmp / cache) files are not part of your source code, so PHOCOA sets up a container directory for these items.

The blog directory inside of this deployment structure is your PHOCOA application directory.

Note

The application directory is the root directory of your PHOCOA application code, and is what you should check in to your version control system. The log and runtime directories are not versioned resources, thus we keep them one level up in the container directory for organizational purposes.

Application Directory Structure

Now let's have a look at the directory structure.

$ ls -l blog/blog 
total 0
drwxr-xr-x   3 alanpins  showcase  102 Sep 11 14:20 classes
drwxr-xr-x   6 alanpins  showcase  204 Sep 11 14:21 conf
drwxr-xr-x   2 alanpins  showcase   68 Sep 11 14:20 modules
drwxr-xr-x   4 alanpins  showcase  136 Sep 11 14:21 propel-build
drwxr-xr-x   3 alanpins  showcase  102 Sep 11 14:20 skins
drwxr-xr-x   4 alanpins  showcase  136 Sep 11 14:20 wwwroot

The classes directory is where all of your classes go. These are classes specific to your application.

The conf directory contains all configuraiton files.

The modules directory is where all components go. These components are the building blocks of your application and include both entire pages and sub-components.

The skins directory is where all skins go.

The wwwroot directory is a public wwwroot that contains the front controller for the PHOCOA project. All public documents (i.e. the tradiditional public www root) go in wwwroot/www/.

Initial Configuration

A new PHOCOA project will have 2 config files. The first is the Apache config file, httpd.conf, followed by the web app config file, webapp.conf.

$ ls -l conf 
total 16
-rw-r--r--   1 alanpins  showcase  2594 May 10 15:41 httpd.conf
-rw-r--r--   1 alanpins  showcase  2770 Sep 11 23:03 webapp.conf

Usually, you won't need to edit any of these files to get things working.

You will need to edit your main Apache conf file to include the conf file for this host, like so:

Include /path/to/blog/blog/conf/httpd.conf

Now restart Apache.

Hello, PHOCOA!

If everything worked, you should be able to go to your web host your specified in the newproject build and see the PHOCOA examples page.

At this point, you should be able to access the site via the web. You should be able to access the application via http://servername/ and see the PHOCOA examples page.

Now, we can move on to the tutorial!