Deploy CakePHP Apps on AppFog the Right Way

Share this article

This article is shared from one of our sister sites, CloudSpring. If you find it helpful, be sure to give them a visit!

This article covers two topics: deploying an application to the AppFog cloud provider, and best practices for a well-structured PHP application. First we’ll build a simple note-taking application using CakePHP and its automated bake command. Then, I’ll show you one way to structure the application separating its components into:
  • application code
  • application data and settings
  • library and vendor code
The app will finally be registered and published to AppFog.

Sign Up with AppFog

AppFog is a Platform as a Service (PaaS) provider built on top of the open-source Cloud Foundry project. It provides support for multiple programming languages and lets us deploy applications to multiple infrastructure providers, such as Amazon AWS, HP Openstack, Microsoft Azure, and Rackspace DFW. Signing up with AppFog is very simple; all you need is an email address and a password and you have access to their free plan which offers 2GB of RAM, 10 services (ex. databases) with a max of 100MB each, and a 50GB data transfer limit. That’s lot for a free service! Also, as they say, you can move your app to any Cloud Foundry compatible service. Go ahead and create your free AppFog account, and then we’ll continue.

Create the Local Application

Download the latest version of CakePHP and extract it on your development machine, and then rename it as your application (I choose FogNotes). Make this directory visible by your web server with a friendly URL (ex. http://fognotes.local), the document root should be the app/webroot directory, and create an empty MySQL database (ex. fognotes_local). In your browser, you should see the default homepage provided by CakePHP. Don’t worry about the warnings – we’ll take care of them soon enough. Now create a directory named data and two subdirectories within it named config and logs. Copy (or move) the app/tmp directory inside data and make this and the logs directory writable to the web server. As a finishing touch, create an alias of CakePHP’s console command cake in the root directory of your application.
~/FogNotes$ ln -s lib/Cake/Console/cake cake
Your directory structure should look like this:
FogNotes/
    app/
    data/
        config/
        logs/
        tmp/
            cache/
            logs/
            sessions/
            tests/
    lib/
        Cake/
    plugins/
    vendors/
    cake
    index.php
By doing this, we have separated the specific application code (app) from the framework (lib/Cake) and libraries (plugins and vendors). Also, the application’s data and settings are all in one separate place (data/*). Now we can we can now update, backup, and maintain each of the components separately. This is much desired in a real-world application! With the directory structure in place, let’s tell CakePHP to use it. We must set the custom temp directory, so edit app/webroot/index.php and paste this code just after the define('ROOT',...)
statement:
<?php
// Custom TMP directory
if (!defined('TMP')) {
    define('TMP', ROOT . DS . 'data' . DS . 'tmp' . DS);
}
Now for the database. Normally the database connection settings are stored inside the app/Config directory in a file named database.php. We’ll modify this setting in order to have the framework look in data/config directory for a file whose named after our current environment instead (ex. data/config/local.php). Copy the file app/Config/database.php.default to app/Config/database.php and replace the DATABASE_CONFIG class with this code:
<?php
class DATABASE_CONFIG
{
    public $default = null;
    public $test    = null;
    public $env     = null;

    /**
     * Switch configuration based on environment
     */
    function __construct() {
        // Check that a suitable environment is defined
        if (!defined('APP_ENV')) {
            return false;
        }

        $this->env = APP_ENV;

        // Try to read database settings from the current ENV file
        $config = Configure::read('Database.config');
        if (!is_array($config)) {
            return false;
        }

        // Load all config database profiles
        foreach ($config as $name => $data) {
            $this->$name = $data;
        }

        // Throw an error if there is no suitable configuration
        if (empty($config['default']) || empty($this->default)) {
            return false;
        }
    }
}
This trick was adapted from an article published in CakePHP developers community by eimermusic. The environment will be defined using the bootstrap file or reading an environment variable provided by AppFog and the associated config file will be loaded. The app/Config/bootstrap.php file is the startup file for the application. Near the bottom of the file, after the Configure::write('Dispatcher.filters'...) statement, insert this code that registers the data/config path with CakePHP:
<?php
// Define a custom reader to search for config files
App::uses('PhpReader', 'Configure');
Configure::config('default',
    new PhpReader(ROOT . DS . 'data' . DS . 'config' . DS));
// Determine the environment
if ($env = getenv('APP_ENV')) {
    if (!defined('APP_ENV')) define('APP_ENV', $env);
}
else {
    if (!defined('APP_ENV')) define('APP_ENV', 'local');
}
AppFog will let us set the APP_ENV variable. If it’s not set, then the app considers itself in local mode. Now skip to the end of the file and paste this code:
<?php
try {
    Configure::load(APP_ENV);
}
catch (ConfigureException $e) {
    // do something, for example exit application
}
The Configure::load() statement tells CakePHP to search the data/config directory for a file named like the current environment (exs. local.php or prod.php). Within this file we can override all the settings defined earlier by the application. A sample local.php config file could be:
<?php
// Load base configuration. Any of the core settings can be
// overridden here. Don't delete the $config var!
$config = array(
    'debug' => 1
);

// If declared in the $config array, String::UUID() crashes
Configure::write('Security.salt', 'SomeSuperSecretLongString');
Configure::write('Security.cipherSeed', 'SomeSuperSecretLongNumber');

// Database settings
Configure::write('Database.config', array(
    'default' => array(
        'datasource' => 'Database/Mysql',
        'persistent' => false,
        'host' => 'localhost',
        'login' => 'root',
        'password' => 'secret_password',
        'database' => 'fognotes_local',
        'prefix' => '',
        'encoding' => 'utf8',
        'unix_socket' => '/tmp/mysql.sock',
    )
));

// Custom Log file settings to ROOT/data/logs/
CakeLog::config('default', array(
    'engine' => 'FileLog',
    'path'   => ROOT . DS . 'data' . DS . 'logs' . DS
));
With all the customization in place, the warning messages in the default home page should disappear.

Create the Application in AppFog

Log into your AppFog console and create a new application. Be sure to choose PHP as the application type, your favorite infrastructure provider (I chose AWS Europe), and give it a name. Then click “Create App” and, in just a couple of seconds, the system will send you to the app’s “Mission Control”. The application with AppFog initally consists of a single index.php file with “Hello World” code; we have to upload our local code. But before we do, we need to bind a database service. Select the “Services” panel, click on the MySQL button, and give it a name (ex. fognotes_prod). The credentials to connect to the service are stored into the environment variable VCAP_SERVICES
. We also need to go to the “Env Variables” panel and set our custom variable. Create a new variable named APP_ENV with the value of “prod” and save. Make a copy of data/config/local.php and name it data/config/prod.php and open it with your editor. We’ll extract the database settings following the guidelines provided by the AppFog docs. Edit the configuration file so that it looks like this:
<?php
// ...other code

// AppFog Extraction
$services_json = json_decode(getenv('VCAP_SERVICES'),true);
$af_mysql_config = $services_json['mysql-5.1'][0]['credentials'];

// Database settings
Configure::write('Database.config', array(
    'default' => array(
        'datasource' => 'Database/Mysql',
        'persistent' => false,
        'host' => $af_mysql_config['hostname'],
        'login' => $af_mysql_config['username'],
        'password' => $af_mysql_config['password'],
        'database' => $af_mysql_config['name'],
        'prefix' => '',
        'encoding' => 'utf8',
    )
));

// ...other code
We could also bind the application to a custom domain or subdomain (for free!) but that’s not the case here. Now we’re almost ready to push our code! In the “Update Source Code” panel, find the instructions to install the af utility on your system. Open a terminal session and navigate into your application root. Follow the instructions to install the CLI tool, then login but don’t download the remote project code. Instead, go ahead with the command af update FogNotes to push the local code to the remote server. In less then a minute, your application is deployed and you can should see the same home screen as your local version. This means the application recognizes the production environment and the remote database.

Adding Some Finishing Touches

We have an empty application deployed, but we must add at least some code and data for our app. We’ll let CakePHP do the hard work. Create the file data/config/notes.sql with the following content:
CREATE TABLE notes (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
    title VARCHAR( 255 ) NOT NULL ,
    content TEXT NOT NULL ,
    created DATETIME NULL DEFAULT NULL ,
    modified DATETIME NULL DEFAULT NULL ,

    INDEX (title, created, modified)
)
ENGINE = INNODB;
Import the file into you local database on the command line or with your favorite MySQL tool. Next, from your app’s root directory, run the command:
~/FogNotes$ ./cake bake
Follow the instructions (it’s really easy!) and create a model, view, and controller for “Notes”, which is the only table in the database. CakePHP will create the right files for you. Then, open the file app/Config/routes.php and replace the first Router::connect() statement with the following code to re-link the home page to the list of notes:
<?php
Router::connect('/', 
  array('controller' => 'notes', 'action' => 'index'));
Reload the local home page and you should have a fully functioning application. Now it’s time to publish the changes. The command af update FogNotes will push the new code. You’ll see a nasty error page if you reload the remote app now. This is because we haven’t created the data table on the remote database. Woops! The easiest way to import tables is by creating a tunnel with the af tunnel command and then connect to the remote database using the info provided by the tunnel itself. Open the tunnel in a console window, select “none” as client type, and then you can use another terminal window to import the SQL file:
mysql --protocol=TCP --host=localhost --port=10000 --user=RemoteUserName 
 --password=RemotePassword RemoteLongDifficultDBName < /path/to/notes.sql
You can also use Sequel Pro if you are on a Mac or MySQL Workbench as long as the tunnel is open. Once the table is in place, the remote application will run smoothly again.

Summary

The organization of the sample application I showed to you here is just one of many techniques you can use to improve your CakePHP development processes. For example, you could store sessions to a file in your local machine and use MongoDB in an AppFog production instance. AppFog is a relatively young PaaS service, but is promising. It’s fast and easy to use, and it’s always evolving. AppFog also lets you clone an entire application, useful to create a staging or bug fixing environment. The rest is up to you, so happy coding! Image via Fotolia

Frequently Asked Questions (FAQs) about Deploying CakePHP Apps on AppFog

What is the difference between deploying CakePHP apps on AppFog and Laravel?

CakePHP and Laravel are both popular PHP frameworks, but they have different deployment processes. Deploying CakePHP apps on AppFog involves setting up the environment, configuring the database, and pushing the app to AppFog. On the other hand, Laravel deployment involves setting up the environment, configuring the app, and using artisan commands to migrate and seed the database. Both processes require a good understanding of the respective frameworks and the deployment platform.

How can I troubleshoot common issues when deploying CakePHP apps on AppFog?

Common issues when deploying CakePHP apps on AppFog can be related to environment configuration, database connection, and app dependencies. To troubleshoot, ensure that your environment variables are correctly set in the AppFog dashboard. Check your database configuration and ensure that it matches with the AppFog settings. Also, ensure that all app dependencies are correctly installed and updated.

What are the benefits of deploying CakePHP apps on AppFog?

Deploying CakePHP apps on AppFog offers several benefits. AppFog provides a scalable and flexible platform for deploying apps. It supports multiple languages and frameworks, including CakePHP. It also offers automated system administration, allowing developers to focus more on coding and less on infrastructure management. Additionally, AppFog provides a range of services such as database, messaging, and caching services, which can be easily integrated with your app.

How can I configure the database for my CakePHP app on AppFog?

Configuring the database for your CakePHP app on AppFog involves setting up the database service on AppFog and updating your app’s database configuration. In the AppFog dashboard, create a new database service and bind it to your app. Then, update your app’s database configuration file with the database service credentials provided by AppFog.

Can I deploy multiple CakePHP apps on AppFog?

Yes, you can deploy multiple CakePHP apps on AppFog. Each app will have its own separate environment and can be managed independently. You can also bind multiple apps to the same database service if they share the same database.

How can I update my CakePHP app on AppFog?

Updating your CakePHP app on AppFog involves pushing the updated app to AppFog. First, make the necessary changes to your app locally. Then, use the AppFog command line tool to push the updated app to AppFog. The platform will automatically update the app and restart it.

What are the security considerations when deploying CakePHP apps on AppFog?

When deploying CakePHP apps on AppFog, it’s important to consider security aspects such as data encryption, user authentication, and app permissions. Ensure that sensitive data is encrypted both in transit and at rest. Implement user authentication to control access to your app. Also, set appropriate permissions for your app to prevent unauthorized access.

How can I monitor my CakePHP app on AppFog?

AppFog provides monitoring tools that allow you to track the performance of your CakePHP app. You can monitor CPU usage, memory usage, and network traffic. You can also set up alerts to be notified of any issues.

Can I roll back changes to my CakePHP app on AppFog?

Yes, you can roll back changes to your CakePHP app on AppFog. If you encounter issues after updating your app, you can use the AppFog command line tool to roll back to a previous version of your app.

How can I scale my CakePHP app on AppFog?

Scaling your CakePHP app on AppFog involves increasing or decreasing the number of app instances or adjusting the memory limit for each instance. You can do this through the AppFog dashboard or using the AppFog command line tool. Scaling allows your app to handle more traffic and provides better performance.

Vito TardiaVito Tardia
View Author

Vito Tardia (a.k.a. Ragman), is a web designer and full stack developer with 20+ years experience. He builds websites and applications in London, UK. Vito is also a skilled guitarist and music composer and enjoys writing music and jamming with local (hard) rock bands. In 2019 he started the BlueMelt instrumental guitar rock project.

Advanced
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week