Article

We ended last time having created an empty CakePHP 3 application. In this post, we will connect it to a database, create a database table, and try our hand at some Cake bake awesomesauce.

First step is firing up our vagrant box, and then ssh into it. Navigate to your events directory that was created in part 2 and run vagrant up and then vagrant ssh.

~/events $ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'puphpet/debian75-x64' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 10200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 7490 (adapter 1)
    default: 22 => 10200 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:10200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Checking for host entries
==> default: adding to (/etc/hosts) : 192.168.56.101  events.dev  # VAGRANT: 245721cf30fa68a26f1d6ba600269a32 (default) / fbefba19-977c-40a8-a199-703d61fd882b
==> default: Setting hostname...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /var/www => /home/xxxx/Development/Personal/events/events
    default: /vagrant => /home/xxxx/Development/Personal/events
    default: /tmp/vagrant-puppet-3/manifests => /home/xxxx/Development/Personal/events/puphpet/puppet
    default: /tmp/vagrant-puppet-3/modules-0 => /home/xxxx/Development/Personal/events/puphpet/puppet/modules
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.
==> default: Running provisioner: shell...
    default: Running: /tmp/vagrant-shell20141118-18238-1uop0bj.sh
==> default: stdin: is not a tty
==> default: Running files in files/startup-once
==> default: Finished running files in files/startup-once
==> default: To run again, delete hashes you want rerun in /.puphpet-stuff/startup-once-ran or the whole file to rerun all
==> default: Running files in files/startup-always
==> default: Finished running files in files/startup-always

~/events $ vagrant ssh
Linux events 3.2.0-4-amd64 #1 SMP Debian 3.2.57-3 x86_64
Welcome to your Vagrant-built virtual machine.

[08:41 AM]-[vagrant@events]-[~] 
~/ $

You are now sshed into the vagrant box, navigate to /var/www (if you are using the supplied PuPHPet vagrant box, the FriendsOfCake box uses /vagrant/www) and take a look a the directory listing.

~/ $ cd /var/www

/var/www $ ls
README.md*  bin/  composer.json*  composer.lock*  config/  index.php*  logs/  phpunit.xml.dist*  plugins/  src/  tests/  tmp/  vendor/  webroot/

You'll see that is our application code that was created in the previous post.

The CakePHP Console

CakePHP includes a brilliant command line tool, simply called the CakePHP console, we will be making extensive use of it, so it's worth taking a quick look at it. Whilst being sshed into the vagrant box, run bin/cake.

/var/www $ bin/cake

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
Current Paths:

* app:  src
* root: /var/www
* core: /var/www/vendor/cakephp/cakephp

Available Shells:

[CORE] bake, i18n, orm_cache, server, test

[app] console

To run an app or core command, type `cake shell_name [args]`
To run a plugin command, type `cake Plugin.shell_name [args]`
To get help on a specific command, type `cake shell_name --help`

If you get a Permission denied error, check your Vagrantfile for owner: 'www-data' and replace it with owner: 'vagrant' and then run vagrant reload in your events directory (on your machine, not the vagrant box).

Out the box, the CakePHP console is shipped with a number of shells.

  • bake - An automated code generation tool. It allows for very quick CRUD (Create, Read, Update, Delete) application creation based on an existing database schema. We will be making use of this soon.
  • i18n - Extracts translatable strings from your application and creates a .pot file which can be used by any number of translation tools
  • orm_cache - CakePHP keeps a cache of database meta data (Tables, fields, data types, etc.). This shell gives an easy interface to refresh that cache in a production application.
  • server - Starts up a PHP 5.4 development server correctly configured for CakePHP
  • test - CakePHP 2.x required running a test shell for unit testing. CakePHP 3 uses PHPUnit directly, the test shell in CakePHP 3 simply gives a message stating how to run tests.
  • console - Fires up a REPL (Read-eval-print-loop) that you can use to interactively use your application. Useful for quickly firing or testing a database query.

CakePHP Configuration

CakePHP 1.x and 2.x kept configuration in two different files, core.php and database.php. The core.php file was littered with Configure::write() method calls, and database.php had a strange class with properties defining your database configuration. With CakePHP 3, this has been greatly simplified, and there is now a single app.php file with your application configuration. Open up config/app.php in your favourite text editor.

<?php
$config = [
/**
 * Debug Level:
 *
 * Production Mode:
 * false: No error messages, errors, or warnings shown.
 *
 * Development Mode:
 * true: Errors and warnings shown.
 */
    'debug' => true,

/**
 * Configure basic information about the application.
 *
 * - namespace - The namespace to find app classes under.
 * - encoding - The encoding used for HTML + database connections.
 * - base - The base directory the app resides in. If false this
 *   will be auto detected.
 * - dir - Name of app directory.
 * - webroot - The webroot directory.
 * - wwwRoot - The file path to webroot.
 * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to
 *   use CakePHP pretty URLs, remove these .htaccess
 *   files:
 *      /.htaccess
 *      /webroot/.htaccess
 *   And uncomment the baseUrl key below.
 * - imageBaseUrl - Web path to the public images directory under webroot.
 * - cssBaseUrl - Web path to the public css directory under webroot.
 * - jsBaseUrl - Web path to the public js directory under webroot.
 * - paths - Configure paths for non class based resources. Supports the
 *   `plugins` and `templates` subkeys, which allow the definition of paths for
 *   plugins and view templates respectively.
 */
    'App' => [
        'namespace' => 'App',
        'encoding' => 'UTF-8',
        'base' => false,
        'dir' => 'src',
        'webroot' => 'webroot',
        'wwwRoot' => WWW_ROOT,
        // 'baseUrl' => env('SCRIPT_NAME'),
        'fullBaseUrl' => false,
        'imageBaseUrl' => 'img/',
        'cssBaseUrl' => 'css/',
        'jsBaseUrl' => 'js/',
        'paths' => [
            'plugins' => [ROOT . DS . 'plugins' . DS],
            'templates' => [APP . 'Template' . DS],
        ],
    ],

/**
 * Security and encryption configuration
 *
 * - salt - A random string used in security hashing methods.
 *   The salt value is also used as the encryption key.
 *   You should treat it as extremely sensitive data.
 */
    'Security' => [
        'salt' => 'd4d4d76fb8528f98d2f40c62ec57efd040d2409d1e86f4f44933ffa81014ada0',
    ],

/**
 * Apply timestamps with the last modified time to static assets (js, css, images).
 * Will append a querystring parameter containing the time the file was modified.
 * This is useful for busting browser caches.
 *
 * Set to true to apply timestamps when debug is true. Set to 'force' to always
 * enable timestamping regardless of debug value.
 */
    'Asset' => [
        // 'timestamp' => true,
    ],

/**
 * Configure the cache adapters.
 */
    'Cache' => [
        'default' => [
            'className' => 'File',
        ],

    /**
     * Configure the cache used for general framework caching. Path information,
     * object listings, and translation cache files are stored with this
     * configuration.
     */
        '_cake_core_' => [
            'className' => 'File',
            'prefix' => 'myapp_cake_core_',
            'path' => CACHE . 'persistent/',
            'serialize' => true,
            'duration' => '+2 minutes',
        ],

    /**
     * Configure the cache for model and datasource caches. This cache
     * configuration is used to store schema descriptions, and table listings
     * in connections.
     */
        '_cake_model_' => [
            'className' => 'File',
            'prefix' => 'myapp_cake_model_',
            'path' => CACHE . 'models/',
            'serialize' => true,
            'duration' => '+2 minutes',
        ],
    ],

/**
 * Configure the Error and Exception handlers used by your application.
 *
 * By default errors are displayed using Debugger, when debug is true and logged
 * by Cake\Log\Log when debug is false.
 *
 * In CLI environments exceptions will be printed to stderr with a backtrace.
 * In web environments an HTML page will be displayed for the exception.
 * With debug true, framework errors like Missing Controller will be displayed.
 * When debug is false, framework errors will be coerced into generic HTTP errors.
 *
 * Options:
 *
 * - `errorLevel` - int - The level of errors you are interested in capturing.
 * - `trace` - boolean - Whether or not backtraces should be included in
 *   logged errors/exceptions.
 * - `log` - boolean - Whether or not you want exceptions logged.
 * - `exceptionRenderer` - string - The class responsible for rendering
 *   uncaught exceptions.  If you choose a custom class you should place
 *   the file for that class in src/Error. This class needs to implement a
 *   render method.
 * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that
 *   extend one of the listed exceptions will also be skipped for logging.
 *   E.g.: `'skipLog' => ['Cake\Network\Exception\NotFoundException', 'Cake\Network\Exception\UnauthorizedException']`
 */
    'Error' => [
        'errorLevel' => E_ALL & ~E_DEPRECATED,
        'exceptionRenderer' => 'Cake\Error\ExceptionRenderer',
        'skipLog' => [],
        'log' => true,
        'trace' => true,
    ],

/**
 * Email configuration.
 *
 * You can configure email transports and email delivery profiles here.
 *
 * By defining transports separately from delivery profiles you can easily
 * re-use transport configuration across multiple profiles.
 *
 * You can specify multiple configurations for production, development and
 * testing.
 *
 * ### Configuring transports
 *
 * Each transport needs a `className`. Valid options are as follows:
 *
 *  Mail   - Send using PHP mail function
 *  Smtp   - Send using SMTP
 *  Debug  - Do not send the email, just return the result
 *
 * You can add custom transports (or override existing transports) by adding the
 * appropriate file to src/Network/Email.  Transports should be named
 * 'YourTransport.php', where 'Your' is the name of the transport.
 *
 * ### Configuring delivery profiles
 *
 * Delivery profiles allow you to predefine various properties about email
 * messages from your application and give the settings a name. This saves
 * duplication across your application and makes maintenance and development
 * easier. Each profile accepts a number of keys. See `Cake\Network\Email\Email`
 * for more information.
 */
    'EmailTransport' => [
        'default' => [
            'className' => 'Mail',
            // The following keys are used in SMTP transports
            'host' => 'localhost',
            'port' => 25,
            'timeout' => 30,
            'username' => 'user',
            'password' => 'secret',
            'client' => null,
            'tls' => null,
        ],
    ],

    'Email' => [
        'default' => [
            'transport' => 'default',
            'from' => 'you@localhost',
            //'charset' => 'utf-8',
            //'headerCharset' => 'utf-8',
        ],
    ],

/**
 * Connection information used by the ORM to connect
 * to your application's datastores.
 * Drivers include Mysql Postgres Sqlite Sqlserver
 * See vendor\cakephp\cakephp\src\Database\Driver for complete list
 */
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            /*
            * CakePHP will use the default DB port based on the driver selected 
            * MySQL on MAMP uses port 8889, MAMP users will want to uncomment 
            * the following line and set the port accordingly
            */
            //'port' => 'nonstandard_port_number',
            'username' => 'my_app',
            'password' => 'secret',
            'database' => 'my_app',
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'cacheMetadata' => true,

            /*
            * Set identifier quoting to true if you are using reserved words or
            * special characters in your table or column names. Enabling this
            * setting will result in queries built using the Query Builder having
            * identifiers quoted when creating SQL. It should be noted that this
            * decreases performance because each query needs to be traversed and
            * manipulated before being executed.
            */
            'quoteIdentifiers' => false,

            /*
            * During development, if using MySQL < 5.6, uncommenting the
            * following line could boost the speed at which schema metadata is
            * fetched from the database. It can also be set directly with the
            * mysql configuration directive 'innodb_stats_on_metadata = 0'
            * which is the recommended value in production environments
            */
            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
        ],

        /**
         * The test connection is used during the test suite.
         */
        'test' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            //'port' => 'nonstandard_port_number',
            'username' => 'my_app',
            'password' => 'secret',
            'database' => 'test_myapp',
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
            'quoteIdentifiers' => false,
            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
        ],
    ],

/**
 * Configures logging options
 */
    'Log' => [
        'debug' => [
            'className' => 'Cake\Log\Engine\FileLog',
            'file' => 'debug',
            'levels' => ['notice', 'info', 'debug'],
        ],
        'error' => [
            'className' => 'Cake\Log\Engine\FileLog',
            'file' => 'error',
            'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
        ],
    ],

/**
 *
 * Session configuration.
 *
 * Contains an array of settings to use for session configuration. The
 * `defaults` key is used to define a default preset to use for sessions, any
 * settings declared here will override the settings of the default config.
 *
 * ## Options
 *
 * - `cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'.
 * - `cookiePath` - The url path for which session cookie is set. Maps to the
 *   `session.cookie_path` php.ini config. Defaults to base path of app.
 * - `timeout` - The time in minutes the session should be valid for.
 *    Pass 0 to disable checking timeout.
 * - `defaults` - The default configuration set to use as a basis for your session.
 *    There are four built-in options: php, cake, cache, database.
 * - `handler` - Can be used to enable a custom session handler. Expects an
 *    array with at least the `engine` key, being the name of the Session engine
 *    class to use for managing the session. CakePHP bundles the `CacheSession`
 *    and `DatabaseSession` engines.
 * - `ini` - An associative array of additional ini values to set.
 *
 * The built-in `defaults` options are:
 *
 * - 'php' - Uses settings defined in your php.ini.
 * - 'cake' - Saves session files in CakePHP's /tmp directory.
 * - 'database' - Uses CakePHP's database sessions.
 * - 'cache' - Use the Cache class to save sessions.
 *
 * To define a custom session handler, save it at src/Network/Session/<name>.php.
 * Make sure the class implements PHP's `SessionHandlerInterface` and set
 * Session.handler to <name>
 *
 * To use database sessions, load the SQL file located at config/Schema/sessions.sql
 */
    'Session' => [
        'defaults' => 'php',
    ],
];

I won 't be going through the whole thing, since the file has plenty of very useful comments in it. All we are going to change in this file for now, is the database configuration details, scroll down to line 205. You 'll see the default datasource configuration.

'default' => [
    'className' => 'Cake\Database\Connection',
    'driver' => 'Cake\Database\Driver\Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'username' => 'my_app',
    'password' => 'secret',
    'database' => 'my_app',
    'encoding' => 'utf8',
    'timezone' => 'UTC',
    'cacheMetadata' => true,

    /*
    * Set identifier quoting to true if you are using reserved words or
    * special characters in your table or column names. Enabling this
    * setting will result in queries built using the Query Builder having
    * identifiers quoted when creating SQL. It should be noted that this
    * decreases performance because each query needs to be traversed and
    * manipulated before being executed.
    */
    'quoteIdentifiers' => false,

    /*
    * During development, if using MySQL < 5.6, uncommenting the
    * following line could boost the speed at which schema metadata is
    * fetched from the database. It can also be set directly with the
    * mysql configuration directive 'innodb_stats_on_metadata = 0'
    * which is the recommended value in production environments
    */
    //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
],

Change the following entries:

  • username: dbuser
  • password: 123
  • database: dbname

You'll notice that I left them to the default PuPHPet settings. In a production environment you'd want these to be more descriptive and much more secure.

If you navigate to http://events.dev you'll see ​​CakePHP is able to connect to the database. where the previous database error used to be.

Database migrations

Since writing of this article, migrations have been included in the default CakePHP 3 application skeleton, so you may not need to manually install it.

Database migrations refer to a way of tracking database schema changes over time. The simplest way is to keep a file with all the SQL schema changes you make, but this can quickly get out of hand and doesn't make it easy to rollback changes. We will be making use of the CakePHP 3 migrations plugin for handling database migrations. The database migrations plugin acts as a wrapper for the excellent Phinx library. We'll install it using composer, ensure you are sshed into the vagrant box and in the /var/www directory. Run composer require cakephp/migrations to install the latest version of the migrations plugin.

/var/www $ composer require cakephp/migrations

Now, open up config/bootstrap.php, find Plugin::load('DebugKit', ['bootstrap' => true]); (around line 168) and add Plugin::load('Migrations'); in the next line. Check that the migrations plugin is working by running bin/cake migrations.

/var/www $ bin/cake migrations

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
Migrations plugin, based on Phinx by Rob Morgan. version 0.3.5

Usage:
  [options] command [arguments]

Options:
  --help           -h Display this help message.
  --quiet          -q Do not output any message.
  --verbose        -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.
  --version        -V Display this application version.
  --ansi              Force ANSI output.
  --no-ansi           Disable ANSI output.
  --no-interaction -n Do not ask any interactive question.

Available commands:
  create     Create a new migration
  help       Displays help for a command
  list       Lists commands
  migrate    Migrate the database
  rollback   Rollback the last or to a specific migration
  status     Show migration status

Let us create our first database migration which we'll call it InitialMigration by running bin/cake migrations create InitialMigration.

/var/www $ bin/cake migrations create InitialMigration

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
using migration path /var/www/config/Migrations
created ./config/Migrations/20141118085121_initial_migration.php

The exact file name will depend on when you ran the command since it is prefixed with the date and time. Open the newly created file, you should see,

<?php

use Phinx\Migration\AbstractMigration;

class InitialMigration extends AbstractMigration
{
    /**
     * Change Method.
     *
     * More information on this method is available here:
     * http://docs.phinx.org/en/latest/migrations.html#the-change-method
     *
     * Uncomment this method if you would like to use it.
     *
    public function change()
    {
    }
    */

    /**
     * Migrate Up.
     */
    public function up()
    {

    }

    /**
     * Migrate Down.
     */
    public function down()
    {

    }
}

There are two methods in this class, and one commented out method. The up() method is run when you migrate up, and the down() method is run when you migrate down (or rollback). The commented out change() method is a special case, if it exists the up() and down() methods do not run, rather Phinx will automatically invert the migrations defined in the change() method when you do a rollback. There are some limitations to the change() method, such as the inability to rollback on dropped tables or columns.

For now we will make use of the up() and down() methods. As a first step for our Events applications we will need a database table to store created events. In this table we will need a primary key, a start date and time, end date and time, a subject line, a description and a flag to indicate if the event runs all day, or not. We will also add in a created and modified date field. Using Phinx, we specify our database schema using simple PHP code. A big advantage of this is that our application is not limited to a single database engine, we could very easily switch to Postgresql, Sqlite or even Microsoft SQL Server. If you want to read up more on Phinix the official documentation is highly recommended.

Let's create our up() method.

/**
 * Migrate Up.
 */
public function up()
{
    $eventsTable = $this->table('events');
    $eventsTable
        ->addColumn('title', 'string', ['length' => 300])
        ->addColumn('description', 'text')
        ->addColumn('start', 'datetime')
        ->addColumn('end', 'datetime')
        ->addColumn('all_day', 'boolean')
        ->addColumn('created', 'datetime')
        ->addColumn('modified', 'datetime')
        ->create();
}

You may be looking at that, and wondering where the primary key is. Phinx will automatically create an auto-increment primary key field called id unless otherwise specified. The Phinx documentation explains how to override this behaviour.

Next, we create our down() method so that we can rollback our database if needed.

/**
 * Migrate Down.
 */
public function down()
{
    $this->dropTable('events');
}

Now we can run our migration and create the table in the database by running bin/cake migrations migrate.

/var/www $ bin/cake migrations migrate

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
using migration path /var/www/config/Migrations
using environment default
using adapter mysql
using database dbname

 == 20141118085121 InitialMigration: migrating
 == 20141118085121 InitialMigration: migrated 0.0153s

All Done. Took 0.0677s

If you look at your database now (Using a tool like MySQL Workbench) you'll see a events table and a phinxlog table. The events table is the one we just created, the phinxlog table is a special one used by Phinx to track which migrations have been installed.

Baking your application

Cake Bake is a powerful tool that allows you to quickly create an application skeleton. While 90% of the time I do not use it, it is still a very useful tool to know how to use. We're going to bake our events table and then customise it further in future posts. Take a look at what Cake Bake offers by running bin/cake bake.

/var/www $ bin/cake bake

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
The following commands can be used to generate skeleton code for your application.

Available bake commands:

- all
- behavior
- fixture
- helper
- controller
- view
- component
- shell
- plugin
- model
- test
- cell
- project

By using `cake bake [name]` you can invoke a specific bake task.

For now we are only interesting in creating the Model, View and Controller for our events table. To do that we run bin/cake bake all events

$ bin/cake bake all events

Welcome to CakePHP v3.0.0-beta3 Console
---------------------------------------------------------------
App : src
Path: /var/www/src/
---------------------------------------------------------------
Bake All
---------------------------------------------------------------
One moment while associations are detected.

Baking table class for Events...

Creating file /var/www/src/Model/Table/EventsTable.php
Wrote `/var/www/src/Model/Table/EventsTable.php`
Deleted `/var/www/src/Model/Table/empty`

Baking entity class for Event...

Creating file /var/www/src/Model/Entity/Event.php
Wrote `/var/www/src/Model/Entity/Event.php`
Deleted `/var/www/src/Model/Entity/empty`

Baking test fixture for Events...

Creating file /var/www/tests/Fixture/EventsFixture.php
Wrote `/var/www/tests/Fixture/EventsFixture.php`
Bake is detecting possible fixtures...

Baking test case for App\Model\Table\EventsTable ...

Creating file /var/www/tests/TestCase/Model/Table/EventsTableTest.php
Wrote `/var/www/tests/TestCase/Model/Table/EventsTableTest.php`

Baking controller class for Events...

Creating file /var/www/src/Controller/EventsController.php
Wrote `/var/www/src/Controller/EventsController.php`
Bake is detecting possible fixtures...

Baking test case for App\Controller\EventsController ...

Creating file /var/www/tests/TestCase/Controller/EventsControllerTest.php
Wrote `/var/www/tests/TestCase/Controller/EventsControllerTest.php`

Baking `index` view file...

Creating file /var/www/src/Template/Events/index.ctp
Wrote `/var/www/src/Template/Events/index.ctp`

Baking `view` view file...

Creating file /var/www/src/Template/Events/view.ctp
Wrote `/var/www/src/Template/Events/view.ctp`

Baking `add` view file...

Creating file /var/www/src/Template/Events/add.ctp
Wrote `/var/www/src/Template/Events/add.ctp`

Baking `edit` view file...

Creating file /var/www/src/Template/Events/edit.ctp
Wrote `/var/www/src/Template/Events/edit.ctp`
Bake All complete.

This creates a basic skeleton to enable you to interact with the Events database table using CakePHP

Havigate to http://events.dev/events and bask in what you've just created with barely any code written!

You can try creating some events, editing them and deleting them, and all you did was run a few commands.

In the next part we will take a step back and look at how CakePHP is put together, the essential parts of the MVC pattern and some best practises for coding your application. In the mean time, play around with your newly created events pages, take a look at the code that was generated by the Bake console and try to see what happens if you change some things around.

Before finishing, shut down your vagrant box again.

$ exit
logout
Connection to 127.0.0.1 closed.

$ vagrant halt
==> default: Attempting graceful shutdown of VM...
==> default: Removing hosts

If you've got any questions or suggestions, please feel free to leave me a comment!

Comments