so the CMS currently only lets you modify (update) one page. i’m going to add in a create button so i can make a new page in my CMS. i’ll also display a list of all pages that currently exist so i can select which one to edit. the list will also have delete functionality.
Create
the create button is simply a link to a create controller. i made the controller ‘create_page.php’ which only has one function at the moment and that is to load the create view v_create.php. in this view, i’ll be asking the user for the title of the page, the uri of the page and the template to use. then the user can enter the page data on the next screen.
first for the title, i’ll need to modify the pages table in the db to have a title field. then i create a basic form for the user to enter this information. something like this in v_create_page.php:
<html lang="en">
<head>
<meta charset="utf-8">
<title>Create Page</title>
</head>
<body>
<?php
// TODO: ajax validation to make sure url is available.
echo form_open('create_page/newPage');
echo form_label('uri', "Enter URI:");
echo form_input('uri');
echo form_label('title', "Enter Title:");
echo form_input('title');
// hard code templates here for now
$templates = array(
'single_column' => 'Single Column',
'double_column' => 'Double Column'
);
echo form_label('template', "Choose template:");
echo form_dropdown('template', $templates, 'single_column');
echo form_submit( 'submit', 'Create' );
echo form_close();
?>
</body>
</html>
i’ve put in some code comments to remind me to do some validation and replace the hard coded templates with database driven ones.
so now i create the newPage function in the controller like so:
public function newPage()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('uri', 'URI', 'trim|required|is_unique[pages.uri]|xss_clean');
$this->form_validation->set_rules('title', 'Title', 'trim|required|xss_clean');
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
if ($this->form_validation->run() == false)
{
$this->load->view('v_create_page');
}
else
{
echo 'success';
$uri = $this->input->post('uri');
$title = $this->input->post('title');
$template = $this->input->post('template');
$this->load->model('m_create_page');
$response = $this->m_create_page->insertPage( $uri, $title, $template );
if ( $response )
{
redirect( 'admin/hub' );
}
else
{
echo 'error!';
print_r( $response );
}
}
}
i’ve added in validation as after i ran my earlier code, i got database errors when you had duplicate uris. so after adding in this validation code i went back to the view and added in the form error fields and altered the input fields to contain the posted data.
echo form_input('uri', set_value('uri'));
echo form_error('uri');
Read
the list on the hub page only shows dummy data at the moment so i’ll modify that to show actual pages from the db. i created a model called m_hub with a rather simple function
<?php
class M_Hub extends CI_Model
{
public function getPages()
{
$query = $this->db->get('pages');
if ($query->num_rows() > 0 )
{
return $query;
}
}
}
?>
then updated the view to spit out the pages instead of dummy data:
<table>
<tr>
<th class="col_page">Page</th>
<th class="col_uri">URL</th>
<th class="col_modified">Modified</th>
<th class="col_actions">Actions</th>
</tr>
<?php
foreach( $pages->result() as $page )
{
?>
<tr>
<td class="col_page"><? echo $page->title; ?></td>
<td class="col_uri"><? echo $page->uri; ?></td>
<td class="col_modified"><? echo $page->modified ?></td>
<td class="col_actions"><a href="">Edit</a> <a href="">Publish</a> <a href="">Delete</a></td>
</tr>
<?
}
?>
</table>
and finally i update the controller to hook it all together
public function index()
{
$this->load->model('m_hub');
$data['pages'] = $this->m_hub->getPages();
$this->load->view('v_hub', $data);
}
Update
i think this will be the trickiest. for now, i’ll just get the edit page to display a text field for title and uri, the wysiwyg editor and the image uploader. each field will be an independent form for now. later, i might modularise them and combine them into one form – i’ll see.
==== NOTE ====
i just discovered my routing method was getting way out of hand so i’ve updated it. here is the new routing rules:
$route['default_controller'] = 'admin';
$route['404_override'] = '';
$route['admin'] = 'admin';
$route['admin/logout'] = 'admin/logout';
$route['admin/(:any)'] = "$1";
$route[':any'] = 'master';
the point of this was to separate all the admin controllers with the public facing pages. so now anything with admin in front of it will be routed to the correct controller. this means i don’t need a separate rule for all admin pages so they don’t look up the db for it. this also means that any links to controllers in the admin must be updated to have a preceding ‘admin/’.
BUG FIXES!
i’ve had a big session of bug fixes to get the edit working so i’ll just dump the code for the various files here:
update_page.php
modified the content variable to be checked for it’s existence.
// check there is content
if ( count( $content ) > 0 )
{
$data['content'] = $content[0];
}
v_update_page.php
- prefixed ‘admin’ to the form submit urls to pass the new route test
- added a check to see if there is any content and to load appropriately. this might be cleaned up later
// if the page has content
if ( isset( $content->text ) && $content->text != '' )
{
echo form_textarea(array( 'name' => 'content', 'class' => 'wysiwyg', 'value' => set_value('content', $content->text )));
}
else
{
echo form_textarea(array( 'name' => 'content', 'class' => 'wysiwyg', 'value' => set_value('content' )));
}
...
if ( isset( $content ) && $content->image != '' )
{
echo '<img src="' . base_url() . $content->image . '" />';
}
m_single_column
made a bunch of changes, entire source here
<?php
class M_Single_Column extends CI_Model
{
public function exists( $id )
{
$this->db->select( 'id' );
$query = $this->db->where( 'id', $id )->get('single_column_pages');
if ( $query->num_rows > 0 )
{
return true;
}
return false;
}
public function getImageURI( $id )
{
$this->db->select( 'image' );
$query = $this->db->where( 'id', $id )->get('single_column_pages');
if ( $query->num_rows > 0 )
{
return $query->row()->image;
}
return false;
}
public function getText( $id )
{
$this->db->select( 'text' );
$query = $this->db->where( 'id', $id )->get('single_column_pages');
if ( $query->num_rows > 0 )
{
return $query->row()->text;
}
return false;
}
public function getAll( $id )
{
return $this->db->where( 'id', $id )->get( 'single_column_pages' );
}
public function insert( $id, $field, $data )
{
$data = array(
'id' => $id,
$field => $data
);
return $this->db->insert( 'single_column_pages', $data );
}
public function update( $id, $field, $data )
{
$this->db->set( $field, $data );
$this->db->where( 'id', $id );
return $this->db->update( 'single_column_pages' );
}
}
?>
upload.php and wysiwyg.php
added an exists check for content
// check if entry for id exists already
$exists = $this->{ $model }->exists( $data['id'] );
if ( !$exists )
{
$success = $this->{$model}->insert( $data['id'], $data['field'], $dbdata );
}
else
{
$success = $this->{ $model }->update( $data['id'], $data['field'], $dbdata );
}
now i also needed to make sure that it knows whether you are updating a page or template, so i’ve made some changes.
the updateField function in the update_page controller now looks like this:
// check the posted data - ignore standard keys
foreach( $this->input->post() as $key => $value )
{
// store table
if ( $key == 'table' )
{
$table = $value;
}
// store field data
if ( $key != 'table' && $key != 'field' && $key != 'id' && $key != 'submit' && $key != 'template' )
{
$data = $value;
}
}
if ( $table == 'pages' )
{
// update pages
$this->load->model( "m_page" );
$response = $this->m_page->updatePage( $this->input->post( 'id' ), $this->input->post( 'field' ), $data );
}
else
{
// update template
$this->load->model( "m_" . $this->input->post('template') );
$response = $this->{"m_" . $this->input->post('template')}->update( $this->input->post( 'id' ), $this->input->post( 'field' ), $data );
}
and m_page model now has an update function
public function updatePage( $id, $field, $data )
{
$this->db->set( $field, $data );
$this->db->where( 'id', $id );
return $this->db->update( 'pages' );
}
there was also an error in the v_update_page view so i updated the form_open for title to read like this:
echo form_open('admin/update_page/updateField');
and with that, updating is done!
Delete
the easiest one! well it’s not that easy…
i created a delete_page controller which looks like this:
<?php if( !defined('BASEPATH')) exit('No direct script access allowed');
class Delete_Page extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function index()
{
// run model code to delete page and associated models here
$this->load->model( "m_" . $template );
$templateResponse = $this->{"m_" . $template}->delete( $id );
if ( $templateResponse )
{
$this->load->model( "m_page" );
$pageResponse = $this->m_page-> deletePage( $id );
if ( $pageResponse )
{
echo 'deleted!';
}
else
{
echo 'page delete error';
}
}
else
{
echo 'template delete error';
}
}
}
?>
and added this href to the link in v_hub.php:
<? echo base_url() . "admin/delete_page/index/" . $page->id . "/" . $page->controller ?>
m_page.php then got itself a delete function:
public function deletePage( $id )
{
return $this->db->where( 'id', $id )->delete( 'pages' );
}
as did m_single_column.php:
public function delete( $id )
{
return $this->db->where( 'id', $id )->delete( 'single_column_pages' );
}
done!
NB: you should add some validation in because if the user enters a URI that already exists, it will fail with a db error.