- general form manipulation at init time * .subForms - provide sub forms (via return) at init time * .validate - validate form data (true for valid, false otherwise) * .populate - populate form from data * * @copyright 2011 Perforce Software. All rights reserved. * @license Please see LICENSE.txt in top-level folder of this distribution. * @version / */ class P4Cms_Form_PubSubForm extends P4Cms_Form { protected $_topic = null; /** * If this form has a topic set, automatically publish to collect * any sub-forms and allow arbitrary modification of the form itself. */ public function init() { if (!$this->hasTopic()) { return; } // collect any sub-forms. $this->publishSubForms(); // allow arbitrary modification of this form. $this->publish(); } /** * Specify the topic to use when publishing this form. * * @param string $topic the topic to use when publishing this form. * @return P4Cms_Form_PubSubForm provides fluent interface * @throws InvalidArgumentException if topic is not a string or null */ public function setTopic($topic) { if (!is_string($topic) && !is_null($topic)) { throw new InvalidArgumentException("Form topic must be a string or null"); } $this->_topic = $topic; return $this; } /** * Get the topic for publishing this form. * * @return string the topic for publishing this form. * @throws InvalidArgumentException if no topic is set. */ public function getTopic() { if ($this->_topic === null) { throw new P4Cms_Form_Exception("No topic set for this form"); } return $this->_topic; } /** * Check if a topic has been set for this form. * * @return bool true if a topic has been set, false otherwise. */ public function hasTopic() { return !is_null($this->_topic); } /** * Collect sub-forms for this form by publishing to the * form topic + '/sub-forms'. Sub-forms are automatically * normalized for consistent presentation and added. * * @return P4Cms_Form_PubSubForm provides fluent interface */ public function publishSubForms() { $feedback = $this->publish('subForms'); // process sub-form feedback. foreach ($feedback as $subForms) { if (!is_array($subForms)) { $subForms = array($subForms); } foreach ($subForms as $subForm) { // skip cases where the subscriber decided not to return a form if (!isset($subForm)) { continue; } if (!$subForm instanceof Zend_Form || !$subForm->getName()) { P4Cms_Log::log( "Encountered invalid pub-sub sub-form.", P4Cms_Log::ERR ); P4Cms_Log::log(print_r($subForm, true), P4Cms_Log::DEBUG); // skip form. continue; } $name = $subForm->getName(); // ensure consistent sub-form markup. static::normalizeSubForm($subForm, $name); // add it. $this->addSubForm($subForm, $name); } } return $this; } /** * Validate the form - publish to the form topic + '/validate' * to allow third-party involvement in validation. * * Subscribers should return true if the data is valid and false * otherwise. Errors can be added directly to the form object. * * @param array $data the data to validate. * @return boolean */ public function isValid($data) { // allow third-parties to make adjustments to the // form and influence the outcome of the validation. $this->publish('preValidate', $data); $isValid = parent::isValid($data); // allow third-parties to validate the form $feedback = $this->publish('validate', $data); // any false feedback means the form is invalid. foreach ($feedback as $valid) { if (!$valid) { $isValid = false; $this->_errorsExist = true; } } return $isValid; } /** * Populate the form from key-value array. Extended to publish to form * topic + '/populate' so that third-parties can participate. * * @param P4Cms_Record|array $values the values to populate the form from. * @return P4Cms_Form_PubSubForm provides fluent interface. */ public function populate($values) { parent::populate($values); // turn records into arrays before publishing so that // subscribers consistently get array input. if ($values instanceof P4Cms_Record) { $values = $values->getValues(); } $this->publish('populate', $values); return $this; } /** * Publish this form. Happens automatically on init() if the topic has been set. * Pass subTopic to append a suffix to the topic. Pass additional args to be * included in the publish call (always includes the form instance by default). * * @param string $subTopic optional - suffix to add to the form topic. * @param mixed $args optional - all arguments besides the topic * are passed as arguments to the handler * @return array the return values of all subscribers. */ public function publish($subTopic = null, $args = null) { $topic = $subTopic ? $this->getTopic() . P4Cms_PubSub::TOPIC_DELIMITER . $subTopic : $this->getTopic(); // inject topic and form into args. $args = func_get_args(); array_splice($args, 0, 1, array($topic, $this)); return call_user_func_array( array('P4Cms_PubSub', 'publish'), $args ); } }