Perforce Chronicle 2012.2/486814
API Documentation

Category_ManageController Class Reference

Manages category operations (e.g. More...

List of all members.

Public Member Functions

 addAction ()
 Add a category.
 deleteAction ()
 Remove a content category.
 editAction (array $params=null)
 Edit a content category.
 indexAction ()
 List categories.
 init ()
 Use management layout for all actions.
 moveAction ()
 Move a category.

Public Attributes

 $contexts

Protected Member Functions

 _restoreCategoriesHierarchy (P4Cms_Model_Iterator $match, P4Cms_Model_Iterator $categories)
 Restore categories hierarchy by appending ancestors to the items contained in match so as for any sub-category, all its ancestors are also present.
 _sortCategoriesRecursively ($categories, $sortKey, $sortFlags, $parentId=null)
 Sort the given list of categories recursively to preserve parent-child relationships.

Detailed Description

Manages category operations (e.g.

add).

Copyright:
2011-2012 Perforce Software. All rights reserved
License:
Please see LICENSE.txt in top-level folder of this distribution.
Version:
2012.2/486814

Member Function Documentation

Category_ManageController::_restoreCategoriesHierarchy ( P4Cms_Model_Iterator match,
P4Cms_Model_Iterator categories 
) [protected]

Restore categories hierarchy by appending ancestors to the items contained in match so as for any sub-category, all its ancestors are also present.

Parent categories that do not match, but must be included, are refered as obligatory. In addition, these obligatory items will be added an extra 'obligatory' field so they can be recognized.

Parameters:
P4Cms_Model_Iterator$matchlist with categories to keep
P4Cms_Model_Iterator$categorieslist with categories where ancestors will be taken from
    {
        // compose list with categories to keep
        $keepIds = array();
        foreach ($match as $category) {
            $keepIds = array_merge(
                $keepIds,
                array($category->getId()),
                $category->getAncestorIds()
            );
        }

        // make keep list unique as there may be duplicates
        $keepIds = array_unique($keepIds);

        // filter categories to keep only selected items
        $categories->filter('id', $keepIds);

        // append and mark obligatory categories
        $obligatory = array_diff($keepIds, $match->invoke('getId'));
        foreach ($categories as $category) {
            if (in_array($category->getId(), $obligatory)) {
                $category->setValue('obligatory', true);
                $match->append($category);
            }
        }
    }
Category_ManageController::_sortCategoriesRecursively ( categories,
sortKey,
sortFlags,
parentId = null 
) [protected]

Sort the given list of categories recursively to preserve parent-child relationships.

Example:

Assume there are 2 categories, A, B where A has 2 childs A/B, A/C. The output is an array iterator with categories in the following order:

  • A, A/B, A/C, B if sorted A to Z
  • B, A, A/C, A/B if sorted Z to A
Parameters:
P4Cms_Model_Iterator$categorieslist of all categories used for getting the children
string | array$sortKeykey to sort categories by
array$sortFlagssorting options
string | null$parentIdoptional - parent category of the generated list (null by default)
Returns:
P4Cms_Model_Iterator list of sorted categories
    {
        // get categories with given parent and sort them
        $childs = $categories
            ->filterByCallback(
                function($category, $parentId)
                {
                    return $category->getParentId() === $parentId;
                },
                $parentId,
                array(P4_Model_Iterator::FILTER_COPY)
            )
            ->sortBy($sortKey, $sortFlags);

        // assemble categories list and append sorted sub-categories below each category
        $sortedCategories = new P4Cms_Model_Iterator;
        foreach ($childs as $category) {
            $sortedCategories[] = $category;
            $sortedChilds       = $this->_sortCategoriesRecursively(
                $categories, $sortKey, $sortFlags, $category->getId()
            );
            foreach ($sortedChilds as $childCategory) {
                $sortedCategories[] = $childCategory;
            }
        }

        return $sortedCategories;
    }
Category_ManageController::addAction ( )

Add a category.

    {
        // enforce permissions.
        $this->acl->check('categories', 'add');

        // set up view
        $view            = $this->view;
        $request         = $this->getRequest();
        $view->shortForm = $request->getParam('short', false);
        $view->headTitle()->set('Add Category');

        // set up form
        $form       = new Category_Form_Manage;
        $view->form = $form;
        $form->setIdPrefix($request->getParam('formIdPrefix'));

        if ($request->isPost()) {
            // if a valid data were posted, try to add the category
            if ($form->isValid($request->getPost())) {
                // populate the form with posted data
                $form->populate($request->getPost());

                // create new category with collected values and save it.
                // try to add a category with posted data; it may fail when
                // ancestors don't exist
                $category = new Category_Model_Category;
                try {
                    $category->setValues($form->getValues())
                             ->setId($form->composeCategoryId())
                             ->save();
                } catch (InvalidArgumentException $e) {
                    // handle the category ancestry does not exist exception
                    if ($e->getMessage() == 'Cannot create new category; category ancestry does not exist.') {
                        $form->getElement('parent')->addError(
                            "Cannot create new category; category ancestor '"
                            . $category->getParentId() . "' does not exist."
                        );
                    } else {
                        // re-thrown other exceptions
                        throw $e;
                    }
                }
            }

            // re-check whether form is valid (i.e. doesn't contain any error messages)
            if ($form->getMessages()) {
                // form is invalid; set bad request response code
                // and assign error messages to the view
                $this->getResponse()->setHttpResponseCode(400);
                $view->errors = $form->getMessages();
                return;
            }

            // if we reached this point, form is valid;
            // set notification message
            $view->message = "Category '{$category->getTitle()}' has been successfully added.";

            // for traditional requests, add notification message and redirect
            if (!$this->contextSwitch->getCurrentContext()) {
                // notify user and return to category list.
                P4Cms_Notifications::add(
                    $view->message,
                    P4Cms_Notifications::SEVERITY_SUCCESS
                );
                $this->redirector->gotoUrl($request->getBaseUrl());
            }

            // assign details about new category to the view
            $view->category = $category;
        }
    }
Category_ManageController::deleteAction ( )

Remove a content category.

    {
        // enforce permissions.
        $this->acl->check('categories', 'manage');

        // require post request method.
        $request = $this->getRequest();
        if (!$request->isPost()) {
            throw new P4Cms_AccessDeniedException(
                "Cannot delete category. Request method must be http post."
            );
        }

        $id       = $request->getParam('id', $request->getParam('category'));
        $category = Category_Model_Category::fetch($id);
        $category->delete();

        $this->view->category = $category;
    }
Category_ManageController::editAction ( array $  params = null)

Edit a content category.

Parameters:
array$paramsThe values to apply
    {
        // enforce permissions.
        $this->acl->check('categories', 'manage');

        // set up view
        $view       = $this->view;
        $view->headTitle()->set('Edit Category');

        // fetch the content category to be edited.
        $request    = $this->getRequest();
        $id         = $request->getParam('category');
        $category   = Category_Model_Category::fetch($id);

        // setup form
        $form       = new Category_Form_Manage;
        $view->form = $form;
        $values     = array_merge(
            $category->getValues(),
            array(
                'parent' => $category->getParentId()
            )
        );
        $form->populate($values);

        // disable unique title check
        $form->setUniqueTitleRequired(false);

        // remove the current category and it's children from parent options.
        $newOptions = array();
        foreach ($form->getElement('parent')->getMultiOptions() as $key => $label) {
            if ($key === $id or strpos($key, "$id/") === 0) {
                continue;
            }
            $newOptions[$key] = $label;
        }
        $form->getElement('parent')->setMultiOptions($newOptions);

        if ($request->isPost()) {
            // if params is specified, we use them to override the existing values
            // else item values come from request
            if (isset($params)) {
                $values = array_merge($category->getValues(), $params);
            } else {
                $values = $request->getPost();
            }

            // if a valid data were posted, try to update the category
            if ($form->isValid($values)) {
                // populate the form with posted data
                $form->populate($values);

                // start a batch in case we're moving
                $adapter = $category->getAdapter();
                $adapter->beginBatch("Edit category $id");

                // if the id has changed, move the category
                $newId = $form->composeCategoryId();
                if ($id !== $newId) {
                    try {
                        Category_Model_Category::move($id, $newId);
                    } catch (InvalidArgumentException $e) {
                        $form->getElement('parent')->addError($e->getMessage());
                    }
                }

                // set form values on category, and save it
                try {
                    $category->setValues($form->getValues())
                             ->setId($newId)
                             ->save();
                } catch (InvalidArgumentException $e) {
                    // handle the category ancestry does not exist exception
                    if ($e->getMessage() == 'Cannot create new category; category ancestry does not exist.') {
                        $form->getElement('parent')->addError(
                            "Cannot create new category; category ancestor '"
                            . $category->getParentId() . "' does not exist."
                        );
                    }

                    // re-throw other exceptions
                    throw $e;
                }
            }

            // re-check whether form is valid (i.e. doesn't contain any error messages)
            if ($form->getMessages()) {
                // form is invalid; revert batch, set bad request response code
                // and assign error messages to the view
                $this->getResponse()->setHttpResponseCode(400);
                $view->errors = $form->getMessages();
                if (isset($adapter)) {
                    $adapter->revertBatch();
                }
                return;
            }

            // at this point, form is valid;
            // attempt to commit the batch - cleanup on failure.
            try {
                $adapter->commitBatch();
            } catch (Exception $e) {
                $adapter->revertBatch();
                throw $e;
            }

            // set notification message
            $view->message = "Category '{$category->getTitle()}' has been updated.";

            // for traditional requests, add notification message and redirect
            if (!$this->contextSwitch->getCurrentContext()) {
                P4Cms_Notifications::add(
                    $view->message,
                    P4Cms_Notifications::SEVERITY_SUCCESS
                );

                $this->redirector->gotoSimple('index');
            }
        }
    }
Category_ManageController::indexAction ( )

List categories.

p4cms.category.grid.actions Modify the passed menu (add/modify/delete items) to influence the actions shown on entries in the Manage Categories grid. P4Cms_Navigation $actions A menu to hold grid actions.

p4cms.category.grid.data.item Return the passed item after applying any modifications (add properties, change values, etc.) to influence the row values sent to the Manage Categories grid. array $item The item to potentially modify. mixed $model The original object/array that was used to make the item. Ui_View_Helper_DataGrid $helper The view helper that broadcast this topic.

p4cms.category.grid.data Adjust the passed data (add properties, modify values, etc.) to influence the row values sent to the Manage Categories grid. Zend_Dojo_Data $data The data to be filtered. Ui_View_Helper_DataGrid $helper The view helper that broadcast this topic.

p4cms.category.grid.populate Adjust the passed iterator (possibly based on values in the passed form) to filter which categories will be shown on the Manage Categories grid. P4Cms_Model_Iterator $items An iterator of Category_Model_Category objects. P4Cms_Form_PubSubForm $form A form containing filter options.

p4cms.category.grid.render Make adjustments to the datagrid helper's options pre-render (e.g. change options to add columns) for the Manage Categories grid. Ui_View_Helper_DataGrid $helper The view helper that broadcast this topic.

p4cms.category.grid.form Make arbitrary modifications to the Manage Categories filters form. P4Cms_Form_PubSubForm $form The form that published this event.

p4cms.category.grid.form.subForms Return a Form (or array of Forms) to have them added to the Manage Categories filters form. The returned form(s) should have a 'name' set on them to allow them to be uniquely identified. P4Cms_Form_PubSubForm $form The form that published this event.

p4cms.category.grid.form.preValidate Allows subscribers to adjust the Manage Categories filters form prior to validation of the passed data. For example, modify element values based on related selections to permit proper validation. P4Cms_Form_PubSubForm $form The form that published this event. array $values An associative array of form values.

p4cms.category.grid.form.validate Return false to indicate the Manage Categories filters form is invalid. Return true to indicate your custom checks were satisfied, so form validity should be unchanged. P4Cms_Form_PubSubForm $form The form that published this event. array $values An associative array of form values.

p4cms.category.grid.form.populate Allows subscribers to adjust the Manage Categories filters form after it has been populated with the passed data. P4Cms_Form_PubSubForm $form The form that published this event. array $values The values passed to the populate method.

    {
        // enforce permissions.
        $this->acl->check('categories', 'manage');

        // setup list options form
        $request        = $this->getRequest();
        $gridNamespace  = 'p4cms.category.grid';
        $form           = new Ui_Form_GridOptions(
            array(
                'namespace'   => $gridNamespace
            )
        );
        $form->populate($request->getParams());

        // set up view
        $view               = $this->view;
        $view->form         = $form;
        $view->pageSize     = $request->getParam('count', 100);
        $view->rowOffset    = $request->getParam('start', 0);
        $view->pageOffset   = round($view->rowOffset / $view->pageSize, 0) + 1;
        $view->showAddLink  = $this->acl->isAllowed('categories', 'add');
        $view->headTitle()->set('Manage Categories');

        // set DataGrid view helper namespace
        $helper = $view->dataGrid();
        $helper->setNamespace($gridNamespace);

        // collect the actions from interested parties
        $actions = new P4Cms_Navigation;
        P4Cms_PubSub::publish($gridNamespace . '.actions', $actions);
        $view->actions = $actions;

        // early exit for standard requests (ie. not json)
        if (!$this->contextSwitch->getCurrentContext()) {
            $this->getHelper('helpUrl')->setUrl('navigation.category.overview.html');
            return;
        }

        // fetch categories and make a copy for later use
        $categories = Category_Model_Category::fetchAll();
        $copy       = new P4Cms_Model_Iterator($categories->getArrayCopy());

        // allow third-parties to influence list
        try {
            P4Cms_PubSub::publish($gridNamespace . '.populate', $categories, $form);
        } catch (Exception $e) {
            P4Cms_Log::logException("Error building categories list.", $e);
        }

        // restore categories hierarchy by appending ancestors to the
        // filtered categories
        $this->_restoreCategoriesHierarchy($categories, $copy);

        // prepare sorting options
        $sortKey    = $request->getParam('sort', 'title');
        $sortFlags  = array(
            P4Cms_Model_Iterator::SORT_NATURAL,
            P4Cms_Model_Iterator::SORT_NO_CASE
        );
        if (substr($sortKey, 0, 1) == '-') {
            $sortKey = substr($sortKey, 1);
            $sortFlags[] = P4Cms_Model_Iterator::SORT_DESCENDING;
        } else {
            $sortFlags[] = P4Cms_Model_Iterator::SORT_ASCENDING;
        }

        // compose list of sorted categories
        $view->categories = $this->_sortCategoriesRecursively($categories, $sortKey, $sortFlags);
    }
Category_ManageController::init ( )

Use management layout for all actions.

    {
        $this->getHelper('layout')->setLayout('manage-layout');
    }
Category_ManageController::moveAction ( )

Move a category.

    {
        // enforce permissions.
        $this->acl->check('categories', 'manage');

        $request    = $this->getRequest();
        $values     = array("parent" => $request->getParam('parent'));

        $this->editAction($values);
    }

Member Data Documentation

Category_ManageController::$contexts
Initial value:
 array(
        'add'       => array('partial' => 'get', 'json' => 'post'),
        'edit'      => array('partial' => 'get', 'json' => 'post'),
        'delete'    => array('partial' => 'get', 'json' => 'post'),
        'index'     => array('json'),
        'move'      => array('json' => 'post')
    )

The documentation for this class was generated from the following file: