Let's get moving. First, we will create the package's directory. Add a new directory in /packages
called cookbook_events
. Inside this directory, create the package's controller file.
You may be familiar with package controllers already; they tell concrete5 about the package, as well as provide functionality for developers to perform advanced tasks.
Enter the following code in controller.php
:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class CookbookEventsPackage extends Package { protected $pkgHandle = 'cookbook_events'; protected $appVersionRequired = '5.6.0.0'; protected $pkgVersion = '0.9.0'; public function getPackageName() { return t('Cookbook Events'); } public function getPackageDescription() { return t('A calendar of events for our website.'); } }
Notice the use of the defined or die
statement at the top of the file. This is required at the top of every PHP file in the package, otherwise concrete5 will reject your add-on if you submit it to the marketplace.
Also, note the use of the t()
function around the package name and description strings. This will allow translators to offer translations of these strings in an easy and consistent way.
We are setting the minimum concrete5 Version to 5.6.0. as we are using some CSS styles that don't fully work on older versions of concrete5. With a little extra work, however, we could support older versions.
Our package will need to create a database table to store the event data. Rather than executing raw SQL, the preferred methodology is to create a db.xml
file that contains all of the tables and fields to be created. concrete5 will read this file when the package is installed and will perform the necessary database operations.
Create the db.xml
file at /packages/cookbook_events/db.xml
.
Enter the following XML code in the file:
<?xml version="1.0"?> <schema version="0.3"> <table name="CookbookEvents"> <field name="id" type="I"> <key /> <unsigned /> <autoincrement /> </field> <field name="title" type="C" size="255"></field> <field name="event_date" type="T"></field> <field name="location" type="C" size="255"></field> <field name="description" type="X2"></field> <field name="created_by" type="I"></field> <field name="created_at" type="T"></field> </table> </schema>
Save this file. This tells concrete5 to create a table named CookbookEvents
, with fields for a title, date, location, description, and some meta data. The use of db.xml
also makes future database upgrades easier when your add-on is updated.
You may recall that this XML file makes use of the ADOdb XML schema format, or AXMLS. You can learn more about AXMLS and the different field types at http://phplens.com/lens/adodb/docs-datadict.htm#xmlschema.
Now that we know what our database table looks like, let's create the model that we will use to interact with the table.
Create a new file at /packages/cookbook_events/models/cookbook_event.php
.
Create the model
class and specify the name of the database table:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class CookbookEvent extends Model { var $_table = 'CookbookEvents'; public function getDate() { return date(DATE_APP_GENERIC_MDY_FULL, strtotime($this->event_date)); } }
Notice how we named the class CookbookEvent
rather than just Event
. This is to prevent collisions with other classes. Since Event
is a fairly common name for a class, it is possible that there could be a conflict. It's always a good idea to make your class names as unique as possible, while still following convention and being easy to understand.
We also added a function to return a formatted version of the event's date. This will come in handy later.
In order for our add-on to have interfaces on the dashboard, we will need to create a few single pages with controllers.
Create a file in /packages/cookbook_events/controllers/dashboard/cookbook_events.php
. This is the root controller file for the add-on. Give it a basic class file:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class DashboardCookbookEventsController extends Controller { public function on_start() { $this->redirect('/dashboard/cookbook_events/list'); } }
The on_start
function will make sure that if anyone visits this page, they will be redirected to the default view showing the events listing. Let's create the controller for that view now.
Now create a new directory at /packages/cookbook_events/controllers/dashboard/cookbook_events/
. Add two files to this directory: add.php
and list.php
.
In list.php
, add the following class:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class DashboardCookbookEventsListController extends Controller { }
Great! Now in add.php
, add another class:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class DashboardCookbookEventsAddController extends Controller { }
Looking good! Our single pages have basic controllers now, but they still need view files.
Create the root view file for our interface at /packages/cookbook_events/single_pages/cookbook_events.php
. Leave this file empty. Create a directory at /packages/cookbook_events/single_pages/cookbook_events
. Add the two files, add.php
and list.php
, to this directory. We can leave these blank for now.
Before we can install our package, we need to make sure that the block type exists as well. This will allow us to automatically install the block type during the package's installation.
This block type that we are creating will show a list of the events that have been entered into the database. It will act as a basic agenda view for the site's events.
Create a new directory at /packages/cookbook_events/blocks
. Now, create another directory in there called cookbook_events
.
The first file that we will want to add to our block is the controller. Create controller.php
in the block's directory.
Enter the following code in controller.php
:
<?php defined('C5_EXECUTE') or die(_("Access Denied.")); class CookbookEventsBlockController extends BlockController { protected $btTable = "btCookbookEvents"; protected $btInterfaceWidth = "350"; protected $btInterfaceHeight = "300"; public function getBlockTypeName() { return t('Events List'); } public function getBlockTypeDescription() { return t('A list of events!'); } }
Notice that we remembered to include the required defined or die
statement at the top of the file. We'll continue prefixing our class names with Cookbook
to allow our classes to avoid conflicting with existing classes.
We also defined the name of the database table that this block type will use. Let's create that table now using the database XML format.
Create a new file in the block directory named db.xml
. Enter the following code in the XML file:
<?xml version="1.0"?> <schema version="0.3"> <table name="btCookbookEvents"> <field name="bID" type="I"> <key /> <unsigned /> </field> <field name="item_limit" type="I"></field> </table> </schema>
This XML code will tell concrete5 to create a new table with two fields: a unique ID to identify the block, and a field to store how many events we want to display.
If you recall from earlier chapters, blocks have three views that can be activated: add, edit, and view. Create add.php
, edit.php
, and view.php
to represent each of these views. In our block, add.php
and edit.php
will show the same HTML, so we will create a fourth file for these views to share named form.php
. Also, add a view.css
file that will be used to apply styles to the frontend of the block.
Leave these files empty for now, as we are ready to install our block!