Actions and option makers

Let's add a bit of action to our plugin

Option makers

Go to the website and edit any content on any page. Put {%%plugin:todo:hello} and save. Now refresh a page. You will see the “hello” text - that is exactly that text the we passed to the plugin in the shortcode above. In the Seotoaster’s plugin system we call it options.

Your plugin could do a lot of cool stuff using options system. Lets create a handler for that option. In seotoaster we call it “option maker”. Modify your plugin’s main class to look as following:

class Todo extends Tools_Plugins_Abstract {

	/**
	 * Init method.
	 *
	 * Use this method to init your plugin's data and variables
	 * Use this method to init specific helpers, view, etc...
	 */
	protected function _init() {
		$this->_view->setScriptPath(__DIR__ . '/system/views/');
	}

    protected function _makeOptionHello() {
        return 'Todo plugin says hello!';
    }
}

All “option makers” should be a protected methods of the plugin’s class and should starts for the “_makeOption” plus option started from the capitalized first letter.

In our case it is _makeOptionHello. Option could return content (but it is not a mandatory) and will be placed instead of the shortcode that calling the option ({%%plugin:todo:hello}). After you refresh a page you will see something like this:

Selection_010

Now, since we know how to work with options, let’s change our hello option to something more useful.

Let’s create an option that will output a small form through which we will add our todos


Modify shortcode {%%plugin:todo:hello} to read {%%plugin:todo:form} and after that modify your plugin’s code to look like like this

lass Todo extends Tools_Plugins_Abstract {

	/**
	 * Init method.
	 *
	 * Use this method to init your plugin's data and variables
	 * Use this method to init specific helpers, view, etc...
	 */
	protected function _init() {
		$this->_view->setScriptPath(__DIR__ . '/system/views/');
	}

    protected function _makeOptionForm() {
        $this->_view->todoForm = new Todo_Forms_Todo();
        return $this->_view->render('form.todo.phtml');_
    }
}
We changed _makeOptionHello to _makeOptionForm and in this option maker we created a form instance
new Todo_Forms_Todo()

and assign it to the view.

Todo_Forms_Todo - instance of the simple Zend_Form. Source code of this form you can find in the full source code example of this plugin on github

form.todo.phtml - view script (template) through wich our form will be rendered and the result of this render will be returned to replace our {%%plugin:todo:form}

todoForm->setAction($this->websiteUrl . 'plugin/todo/run/add/'); echo $this->todoForm; ?>

And finally you will have something similar on your page

Selection_013

Actions

Now we have a form, but we can’t submit it yet, because our form has no action. Let’s create  a method that will handle our form submission. In the Seotoaster’s plugin system we call it “actions

Actions - public methods that end with the word “Action

Let’s add an “add” action. Modify your plugin and add new public method “addAction”. Now your plugin main class should look like the example bellow

public function addAction() {
        if(!$this->_request->isPost()) {
            throw new Exceptions_SeotoasterPluginException('Direct access is not allowed');
        }
        $todoForm = new Todo_Forms_Todo();
        if($todoForm->isValid($this->_request->getParams())) {
            //save our todo item
        }
        $this->_redirect($this->_proccessFormMessages($todoForm->getMessages()), true);
    }

Now we have a form handler but we need to save our todos into the database. Lets teach our plugin to do that. Put following sql snippets into the install and uninstall sql respectively

install.sql
CREATE TABLE IF NOT EXISTS `plugin_todo` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` tinytext COLLATE utf8_unicode_ci NOT NULL,
  `status` enum('A','D') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'A',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
uninstall.sql
DROP TABLE IF EXISTS `plugin_todo`;

Now go to plugin management screen and uninstall the Todo plugin and then install it again. After this install you will have the “plugin_todo” table in the database. We’re almost ready to save our todos. Now we have to create a model and a mapper (seotoaster / zend way to work with the database). Full source code of the model and mapper you can find in the repository on the github

Finally let's finish with add action and see what else can we do with the plugin. Modify your plugin’s source to look similar to the example below. First off all add and initialize flash messanger helper [read this for more details] to be able to show some feedback to the user

class Todo extends Tools_Plugins_Abstract {

    private $_flashMessenger = null;

	/**
	 * Init method.
	 *
	 * Use this method to init your plugin's data and variables
	 * Use this method to init specific helpers, view, etc...
	 */
	protected function _init() {
        $this->_flashMessenger = Zend_Controller_Action_HelperBroker::getStaticHelper('FlashMessenger');
		$this->_view->setScriptPath(__DIR__ . '/system/views/');
	}

Now modify add action and option maker to look like the example bellow

protected function _makeOptionForm() {
        $htis->_view->error              = $this->_sessionHelper->error;
        $this->_view->messages           = $this->_flashMessenger->getMessages();
        $this->_sessionHelper->pluginUrl = $this->_seotoasterData['url'];

        $this->_view->todoForm           = new Todo_Forms_Todo();
        return $this->_view->render('form.todo.phtml');
    }

    public function addAction() {
        if(!$this->_request->isPost()) {
            throw new Exceptions_SeotoasterPluginException('Direct access is not allowed');
        }
        $todoForm = new Todo_Forms_Todo();
        if($todoForm->isValid($this->_request->getParams())) {
            $mapper = Todo_Models_Mapper_TodoMapper::getInstance();
            $todo   = $mapper->save(new Todo_Models_Model_Todo($todoForm->getValues()));
            if($todo instanceof Todo_Models_Model_Todo) {
                $this->_redirect(array('Todo item added.'));
            }
            $this->_redirect(array('Cannot create a todo item. Try again later'), true);
        }
        $this->_redirect($this->_proccessFormMessages($todoForm->getMessages()), true);
    }

And finally add two private methods for the redirect and procces form messages

/**
     * Set the proper feedback messages and redirects user to the correct page
     *
     * @param array $messages
     * @param bool $error
     */
    private function _redirect($messages = array(), $error = false) {
        $this->_sessionHelper->error = $error;
        if(sizeof($messages) > 1) {
            array_walk($messages, function($message, $key, $params) {
                $params['messenger']->addMessage($message);
            }, array('messenger' => $this->_flashMessenger));
        } else {
            $this->_flashMessenger->addMessage($messages[0]);
        }
        $this->_redirector->gotoUrlAndExit($this->_sessionHelper->pluginUrl);
    }

    /**
     * Proccess form validation error messages
     *
     * @param $messages
     * @return array
     */
    private function _proccessFormMessages($messages) {
        $proccessedMessages = array();
        foreach($messages as $field => $messageData) {
            $fieldMessages = array_values($messageData);
            foreach($fieldMessages as $fieldMessage) {
                $proccessedMessages[] = $field . ': ' . $fieldMessage;
            }
        }
        return $proccessedMessages;
    }

That’s it now we are able to add the todo and save it to the database and send some feedback to the user. Awesome. To finish this plugin we have to add a few actions, such as delete - to delete todos from the database, status - to switch todo’s status (done / active). And the last thing we have to add is one more option - {%%plugin:todo:list} - to display a list of our todos. We will skip that part because creation of those actions and option are similar to what we have done with the add action and form option. You can get the full source code of the plugin on the github

DevNews