Chapter 6. Managing Content

Over the course of this book, you have built the foundation for your CMS project. You started by creating the application framework and then added the core models and classes that are required to serve your CMS. Now you are ready to manage content.

Creating and Updating Content Pages

Before you get into coding, you need to define how the page editor interface is going to work. It is common for complex systems to use a dedicated administrator interface. This gives the developers more flexibility. For a straightforward project like this, I recommend the simpler approach of editing pages in place.

The actual content management will be quite simple since you already created the Model_Page and Model_ContentNode classes, which handle the low-level database management, while the higher-level CMS_Content_Item_Abstract class handles the page-level logic.

In this chapter, you will create a new content item class for standard CMS pages (which will extend the abstract CMS_Content_Item_Abstract class). Then you will create the controller and interface for the page section, which will handle the page editing and rendering.

Creating the Page Content Item Class

In the previous chapter, you created an abstract class for the CMS content items, CMS_Content_Item_Abstract. This class handles the required logic to manage the flexible data structure that you implemented with the node pattern. Now you are ready to create a concrete implementation of this class, CMS_Content_Item_Page.

The first thing you need to do is determine which fields you want to have in a standard content page. In this case, there will be two main views for a page: a list view and open view. The list view will render a list of all the pages, with the title, thumbnail, and description. Then the open view will display the complete page. You will need the fields listed in Table 6-1 to manage this.

Table 6.1. The Standard Page Fields

Field

Description

Id

The primary key for the page

Name

The name of the page

Headline

The headline for the page

Image

The path to the page image

Description

A short description of the page

content

The full page content

Note

You will save the page images in /public/images/upload, so create this folder now.

The abstract content item class handles all the CRUD functionality for the content item, so all you need to do is define each of these properties. Note that the base abstract class already has the id, name, and parent_id properties, but I prefer to include them anyway, because it makes the content items more intuitive to read.

Add a new file to the library/CMS/Content/Item folder named Page.php. Define the CMS_Content_Item_Page class in this file (see Listing 6-1), and then set each of the properties listed in Table 6-1.

Example 6.1. The CMS_Content_Item_Page Class in library/CMS/Content/Item/Page.php

<?php
class CMS_Content_Item_Page extends CMS_Content_Item_Abstract
{
    public $id;
    public $name;
    public $headline;
    public $image;
    public $description;
    public $content;
}
?>

Creating the Page Controller

Now you need to create the page controller and its associated view script. You can do this using Zend_Tool by executing the command in Listing 6-2.

Example 6.2. Creating the Page Controller and Views with Zend_Tool

zf create controller page

Creating the Page Form

The next step is to create the form that you will use to create and update pages. Create a new file in the application/forms folder named Page.php. Then you need to add a control for each of the page fields. The ID will be a hidden control, while the name and headline can be text controls. The image should be a file control (you will need to set the form's encoding type to multipart/form-data to use this control). Finally, add a text area control for the description and content. Listing 6-3 shows the completed page form.

Example 6.3. The Page Form in application/forms/PageForm.php

<?php
class Form_PageFormForm extends Zend_Form
{
    public function init()
    {
        $this->setAttrib('enctype', 'multipart/form-data'),

        // create new element
        $id = $this->createElement('hidden', 'id'),
        // element options
        $id->setDecorators(array('ViewHelper'));
        // add the element to the form
        $this->addElement($id);

        // create new element
        $name = $this->createElement('text', 'name'),
        // element options
        $name->setLabel('Page Name: '),
        $name->setRequired(TRUE);
        $name->setAttrib('size',40);
        // add the element to the form
        $this->addElement($name);

        // create new element
        $headline = $this->createElement('text', 'headline'),
        // element options
        $headline->setLabel('Headline: '),
        $headline->setRequired(TRUE);
        $headline->setAttrib('size',50);
// add the element to the form
        $this->addElement($headline);

        // create new element
        $image = $this->createElement('file', 'image'),
        // element options
        $image->setLabel('Image: '),
        $image->setRequired(FALSE);
        // DON'T FORGET TO CREATE THIS FOLDER
        $image->setDestination(APPLICATION_PATH . '/../public/images/upload'),
        // ensure only 1 file
        $image->addValidator('Count', false, 1);
        // limit to 100K
        $image->addValidator('Size', false, 102400);
        // only JPEG, PNG, and GIFs
        $image->addValidator('Extension', false, 'jpg,png,gif'),
        // add the element to the form
        $this->addElement($image);

        // create new element
        $description = $this->createElement('textarea', 'description'),
        // element options
        $description->setLabel('Description: '),
        $description->setRequired(TRUE);
        $description->setAttrib('cols',40);
        $description->setAttrib('rows',4);
        // add the element to the form
        $this->addElement($description);

        // create new element
        $content = $this->createElement('textarea', 'content'),
        // element options
        $content->setLabel('Content'),
        $content->setRequired(TRUE);
        $content->setAttrib('cols',50);
        $content->setAttrib('rows',12);
        // add the element to the form
        $this->addElement($content);

        $submit = $this->addElement('submit', 'submit', array('label' => 'Submit'));
    }
}
?>

Rendering the Page Form

Next you need to create a new action in the page controller to create the new page. You can do this with the Zend_Tool's create action command from your command prompt, as shown in Listing 6-4.

Example 6.4. Creating the Create Page Action with Zend_Tool

zf create action create page

Now open the page controller, and locate the newly created createAction() method. Create a new instance of the Form_PageForm() class, and pass this to the view, as shown in Listing 6-5.

Example 6.5. The Updated createAction() Method in application/controllers/PageController.php

public function createAction()
{
    $pageForm = new Form_PageForm();
    $pageForm->setAction('/page/create'),
    $this->view->form = $pageForm;
}

Now open the view script that Zend_Tool created for the createAction() method (application/views/scripts/page/create.phtml). Add a descriptive headline to the page, and render the form, as shown in Listing 6-6.

Example 6.6. The Updated Create Page View Script in application/views/scripts/page/create.phtml

<h2>Create a new page</h2>
<p>To create a new page complete this form and click submit...</p>
<?php echo $this->form; ?>

Now if you point your browser to http://localhost/page/create, you should see the page form, as shown in Figure 6-1. Create a test page, and submit the form.

The create page form

Figure 6.1. The create page form

Inserting the New Page

When you submit the page form, it posts back to the page controller's create action.

You need to update this action to evaluate whether the request is a postback. If it is a postback, then you need to populate the form and validate it. If it passes the validation, then you are ready to create the new page.

To create the page, you need to create a new instance of the CMS_Content_Item_Page class and populate it with the values from the page form. Since you also have one file field, you need to download he file (the page image) and then set the image property in the page object to the path to the image that was uploaded. Listing 6-7 shows the updated createAction() method.

Example 6.7. The Updated Page Controller createAction() in application/controllers/PageController.php

public function createAction()
{
    $pageForm = new Form_PageForm();
    if($this->getRequest()->isPost()) {
        if($pageForm->isValid($_POST)) {
            // create a new page item
            $itemPage = new CMS_Content_Item_Page();
            $itemPage->name = $pageForm->getValue('name'),
            $itemPage->headline = $pageForm->getValue('headline'),
            $itemPage->description = $pageForm->getValue('description'),
            $itemPage->content = $pageForm->getValue('content'),
            // upload the image
            if($pageForm->image->isUploaded()){
                $pageForm->image->receive();
                $itemPage->image = '/images/upload/' .
                    basename($pageForm->image->getFileName());
            }
            // save the content item
            $itemPage->save();
            return $this->_forward('list'),
        }
    }
    $pageForm->setAction('/page/create'),
    $this->view->form = $pageForm;
}

Managing Pages

Now that you have a way to add pages to your site, you need a way to manage them. The first thing you will need to do is create a list of all the current pages. Then you will need to add links to this list to edit and delete these pages.

The first step of this process is to create an action in the page controller to list all the current pages. As your site grows, you may need to allow site administrators to filter and sort this list to make finding a specific page easier, but for now just return a list sorted by the title. Create the list action in the page controller using Zend_Tool, as shown in Listing 6-8.

Example 6.8. Creating the Page Controller List Action with Zend_Tool

zf create action list page

Now update the listAction() method. Create a new instance of the page model, and then fetch all the current pages. Next pass the record set to the view to render the page list (Listing 6-9).

Example 6.9. The List Action in application/controllers/PageController.php

public function listAction()
{
    $pageModel = new Model_Page();
    // fetch all of the current pages
    $select = $pageModel->select();
    $select->order('name'),
    $currentPages = $pageModel->fetchAll($select);
    if($currentPages->count() > 0) {
        $this->view->pages = $currentPages;
    }else{
        $this->view->pages = null;
    }
}

Next you need to create the view script to display the list of the pages. This view script will render the pages as a table, using the partialLoop() view helper and a partial script to render each row.

Create a new file for the page row partial in the application/views/scripts/partials folder named _page-row.phtml. This partial needs fields for the page title and for the links to edit or delete each page (Listing 6-10).

Example 6.10. The Page Table Row Partial in application/views/scripts/partials/_page-row.phtml

<tr>
    <td class='links'>
        <a href='/page/edit/id/<?php echo $this->id;?>'>Update</a>
        <a href='/page/delete/id/<?php echo $this->id;?>'>Delete</a>
    </td>
    <td><?php echo $this->name ?></td>
</tr>

Now that this partial script is set up, you can create the view script to list the rows. Open application/views/scripts/page/list.phtml and set the header as with the other view scripts. Then check to see whether there are any pages, and if there are, create a table to render them. Use the partialLoop() helper to render each of the page rows. If there are no pages, then display a message letting the user know that there are no pages currently. You should also add a link to create a new page (Listing 6-11).

Example 6.11. The List Pages View Script in application/views/scripts/page/list.phtml

<h2>Current Pages</h2>
<?php
if($this->pages != null) {
?>
<table class='spreadsheet' cellpadding='0' cellspacing='0'>
    <tr>
<th>Links</th>
        <th>Name</th>
    </tr>
    <?php echo $this->partialLoop('partials/_page-row.phtml', $this->pages); ?>
</table>
<?php }else{?>
<p>You do not have any pages yet.</p>
<?php }?>
<p><a href='/page/create'>Create a new page</a></p>

You should note that the user row has links to update or delete the user. These links assume that there is an update and a delete action in the user admin controller.

Editing an Existing Page

Now that you can create pages, you need a way to update them. To do this, you need to add a new action to the page controller. You will pass this action the page ID that you want to edit as a request parameter. This action will load the corresponding page and then pass this data to the page form.

Opening a Page to Edit

To get started, you need to create the edit action in the page controller. Create this action using Zend_Tool, as shown in Listing 6-12.

Example 6.12. Creating the Page Controller's Edit Action Using Zend_Tool

zf create action edit page

You will use the same form to edit the pages as you did to create the page, which you will populate with the data from the page item. Note that CMS_Content_Item has the toArray() method, which converts all of its properties to an array. This was added specifically to make populating forms, which expect an array of data, as easy as possible. Also note that there is no way to preview the page image. You will need to add this functionality. You could update the form, but then you would need to hide this element when you are creating a page. A simpler solution is just to add the image preview element in the editAction() method, as shown in Listing 6-13.

Example 6.13. The Edit Action in application/default/controllers/PageController.php

public function editAction()
{
    $id = $this->_request->getParam('id'),
    $itemPage = new CMS_Content_Item_Page($id);
    $pageForm = new Form_PageForm();
    $pageForm->setAction('/page/edit'),
    $pageForm->populate($itemPage->toArray());

    // create the image preview
    $imagePreview = $pageForm->createElement('image', 'image_preview'),
// element options
    $imagePreview->setLabel('Preview Image: '),
    $imagePreview->setAttrib('style', 'width:200px;height:auto;'),
    // add the element to the form
    $imagePreview->setOrder(4);
    $imagePreview->setImage($itemPage->image);
    $pageForm->addElement($imagePreview);

    $this->view->form = $pageForm;
}

Next you need to update the edit.phtml view script. This script is virtually identical to the create.phtml file, as shown in Listing 6-14.

Example 6.14. The Edit Page View in application/views/scripts/page/edit.phtml

<h2>Update page</h2>
<?php echo $this->form; ?>

Updating the Page

Now you need to process the form and update the page. This form will post back to the edit action, as the create action did. You will need to update this action to process the form on the postback. When the form is posted back, you validate the form data and then update the page if it passes the validation (see Listing 6-15).

Example 6.15. The Updated Edit Action in application/controllers/PageController.php

public function editAction()
{
    $id = $this->_request->getParam('id'),
    $itemPage = new CMS_Content_Item_Page($id);
    $pageForm = new Form_PageForm();
    $pageForm->setAction('/page/edit'),
    if($this->getRequest()->isPost()) {
        if($pageForm->isValid($_POST)) {
            $itemPage->name = $pageForm->getValue('name'),
            $itemPage->headline = $pageForm->getValue('headline'),
            $itemPage->description = $pageForm->getValue('description'),
            $itemPage->content = $pageForm->getValue('content'),
            if($pageForm->image->isUploaded()){
                $pageForm->image->receive();
                $itemPage->image = '/images/upload/' .
                    basename($pageForm->image->getFileName());
            }
            // save the content item
            $itemPage->save();
            return $this->_forward('list'),
        }
}
    $pageForm->populate($itemPage->toArray());

    // create the image preview
    $imagePreview = $pageForm->createElement('image', 'image_preview'),
    // element options
    $imagePreview->setLabel('Preview Image: '),
    $imagePreview->setAttrib('style', 'width:200px;height:auto;'),
    // add the element to the form
    $imagePreview->setOrder(4);
    $imagePreview->setImage($itemPage->image);
    $pageForm->addElement($imagePreview);

    $this->view->form = $pageForm;
}

Deleting Pages

The final step in managing pages is to create a method to delete them. This is a very straightforward process since the parent class of the Content model already has a method to delete a page and all of its content nodes. You simply create an action in the page controller to delete the page and then forward to the page list action, as shown in Listing 6-16.

Example 6.16. The Delete Page Action in application/default/controllers/PageController.php

public function deleteAction ()
{
    $id = $this->_request->getParam('id'),
    $itemPage = new CMS_Content_Item_Page($id);
    $itemPage->delete();
    return $this->_forward('list'),
}

Rendering Pages

Now that the tools are in place to create, update, and delete pages, you are ready to start publishing content. You will create two main pages in this section:

  • Index: This view will display a teaser list of the recently created pages.

  • Open: This view will open a selected page.

The Home Page

The default page for your CMS will render a list of the most recently added pages, like most blog packages. Each item in the list will have the title of the page (which will link to the page) and the teaser.

Rendering the Most Recent Pages

To get started, create a new method in the Page model to fetch the most recently created pages. This method will need to fetch the pages in the order that they were created. It then needs to cycle through these pages, opening each one. Finally, it should return these pages as an array that you can pass to the view (Listing 6-17).

Example 6.17. The getRecentPages() Method in application/models/Page.php

public function getRecentPages ($count = 10, $namespace = 'page')
{
    $select = $this->select();
    $select->order = 'date_created DESC';
    $select->where('namespace = ?', $namespace);
    $select->limit($count);
    $results = $this->fetchAll($select);
    if ($results->count() > 0) {
        //cycle through the results, opening each page
        $pages = array();
        foreach ($results as $result) {
            $pages[$result->id] = new CMS_Content_Item_Page($result->id);
        }
        return $pages;
    } else {
        return null;
    }
}

The three most recent items will be featured items. These items will be rendered as blocks with thumbnails and the full description. The remaining recent items will simply be links.

To do this, you need to create a new instance of the page model and fetch the results of the getRecentPages() method. Once you have this array, shift the first three items off the beginning of the array, and pass these to the view as the featured items. Pass the remaining array to the view as the recent pages, as shown in Listing 6-18.

Example 6.18. The Index Action in application/controllers/PageController.php

public function indexAction()
{
    $pageModel = new Model_Page();
    $recentPages = $pageModel->getRecentPages();

    if(is_array($recentPages)) {
        // the 3 most recent items are the featured items
        for($i = 1; $i <= 3; $i++) {
            if(count($recentPages) > 0) {
                $featuredItems[] = array_shift($recentPages);
            }
        }
        $this->view->featuredItems = $featuredItems;
if(count($recentPages) > 0) {
            $this->view->recentPages = $recentPages;
        } else {
        $this->view->recentPages = $null;
        }
    }
}

Now you need to update the index.phtml view script to render these. The first three items, or featured items, will be rendered as blocks. These blocks will consist of the headline, a thumbnail (which you will just resize with CSS), and the page description. The remaining items will be rendered as a list of links, as shown in Listing 6-19.

Example 6.19. The Page Index Action View Script in application/views/scripts/page/index.phtml

<h2>Featured Content</h2>
<?php
if($this->featuredItems) {
    foreach ($this->featuredItems as $page) {
?>
<div class='featuredItem'>
    <h3><a href='/page/open/id/<?php echo $page->id; ?>'>
        <?php echo $page->headline?></a></h3>
    <img src='<?php echo $page->image;?>' alt='<?php echo $page->headline?>' />
    <p><?php echo $page->description; ?></p>
    <br style='clear:left;' />
</div>
<?php
 }
}

if($this->recentPages) { ?>
<div class='recentPages'>
    <h3>More Pages</h3>
    <ul>
    <?php foreach ($this->recentPages as $page) {?>
    <li><a href='/page/open/id/<?php echo $page->id; ?>'>
        <?php echo $page->headline?></a></li>
    <?php } ?>
    </ul>
</div>
<?php } ?>

Now when you point your browser to http://localhost/page, you should see the list with no particular style. Take a moment now to style the featuredItem blocks by updating /public/skins/blues/css/layout.css, as shown in Listing 6-20.

Example 6.20. Adding the featuredItem Styles to the Blues Skin in /public/skins/blues/css/layout.css

.featuredItem{
    padding:5px 10px;
    margin:10px;
    width:420px;
    min-height:100px;
    -moz-border-radius: 5px;
    border:1px solid #749BCE;
}

.featuredItem h3{
    margin-bottom:5px;
}

.featuredItem h3 a{
    color:#000;
    text-decoration:none;
}

.featuredItem h3 a:hover{
    text-decoration:underline;
}

.featuredItem img{
    width:120px;
    height:auto;
    float:left;
    margin:0 10px 10px 0;
}

.featuredItem ul{
    padding:5px 30px;
}

Now when you refresh your browser, the featured item blocks should be cleanly laid out with the headline, a thumbnail, and the description, as shown in Figure 6-2.

The styled featured page list

Figure 6.2. The styled featured page list

Setting This Page As Your Site's Home Page

The Zend Framework operates on the principle of setting logical defaults but allows you to override these defaults as needed. By default, the site's home page renders the following:

  • Module: Default

  • Controller: Index

  • Action: Index

The default module and action are OK for this project, but you want to override the default controller to set the previous recent page list as the home page. The Zend_Application's Zend_Application_Resource_Frontcontroller resource makes this very easy to change. You simply have to update the application.ini config file, setting the resources.frontController.defaultControllerName property, as shown in Listing 6-21.

Example 6.21. Updating the Default Controller in application/configs/application.ini

resources.frontController.defaultControllerName = "page"

Opening a Page

Now you need to create an action in your page controller to open the pages. Most of the code that you need is already written, so it is a simple process. To get started, create the open action in the page controller using Zend_Tool, as shown in Listing 6-22.

Example 6.22. Creating the Open Page Action with Zend_Tool

zf create action open page

The next step is updating the open action. You will pass the open action the ID of the page to open as a URL parameter. The open action will then need to confirm that the page exists. If it does not exist, then it will need to throw an exception, which the error handler will capture. If it does exist, then it will create a new instance of CMS_Content_Item_Page. It will pass the page ID to the CMS_Content_Item_Page, which will in turn load the page data. Then it needs to pass this page object to the view to render, as shown in Listing 6-23.

Example 6.23. The Open Action in application/controllers/PageController.php

public function openAction()
{
    $id = $this->_request->getParam('id'),
    // first confirm the page exists
    $pageModel = new Model_Page();
    if(!$pageModel->find($id)->current()) {
        // the error handler will catch this exception
        throw new Zend_Controller_Action_Exception(
            "The page you requested was not found", 404);
}else{
        $this->view->page = new CMS_Content_Item_Page($id);
    }
}

Next you need to update the view script, rendering the page content. You can see the completed view script in Listing 6-24. Note that I like to wrap the page with the openPage div. This gives you specific control over the page-level items.

Example 6.24. The Open Page Script in application/views/scripts/page/open.phtml

<div id="openPage">
    <h2><?php echo $this->page->headline?></h2>
    <blockquote><?php echo $this->page->description; ?></blockquote>
    <img id='mainImage' src='<?php echo $this->page->image; ?>'
        alt='<?php echo $this->page->headline?>' />
    <?php echo $this->page->content ?>
</div>

Finally, you need to style this page. I will make this very simplistic at this point, simply resizing the main page image, floating it right, and updating the description text (see Listing 6-25). Feel free to get as creative as you like!

Example 6.25. Adding the Open Page Styles to the Blues Skin in /public/skins/blues/css/layout.css

#openPage{
    width:520px;
}

#openPage blockquote{
    padding:10px;
    font-style:italic;
}

#openPage img#mainImage{
    width:320px;
    height:auto;
    margin:0 0 10px 10px;
    float:right;
}

Now you have a simple yet functional CMS. If you navigate to http://localhost and click one of the headlines, the page should open and look something like Figure 6-3.

The open page

Figure 6.3. The open page

Summary

In this chapter, you learned how to use the abstract data models that you created in the previous chapter to manage your site's standard content pages. You created your CMS page form and then created the functions to create, read, update, and delete content pages. Once this CRUD management was out of the way, you created the list (your default view) and open views for the CMS.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset