_dfRelations = array( * array( * '_element' => 'moreInfoType', * 'node' => '[name="moreInfoType"]:checked', * 'group' => '[name="moreInfoType"]', * 'event' => 'change', * 'rules' => array( * array( * 'value' => 'none', * '_elements' => array() * ), * array( * 'value' => 'url', * '_elements' => array('moreInfoUrl') * ), * array( * 'value' => 'page', * '_elements' => array('moreInfoPage') * ), * ) * ), * ); * @var array Node relations that will be converted to format compatible with jQuery.dynamicForm() */ protected $_dfRelations = []; /** * @var array List on elements names that will be preserved in method $this->_dfClearUnusedValues() */ protected $_dfPreserveFields = []; /** * Clears values of hidden nodes (values of elements listed in $this->_dfPreserveFields will be preserved) * @param array $values * @throws \Exception */ public function dfClearUnusedValues(array &$values) { foreach ($this->_dfRelations as $relation) { if (!isset($relation['element'])) { continue; } $name = $relation['element']; if (!array_key_exists($name, $values)) { continue; } $value = $values[$name]; $available = []; $unavailable = []; foreach ($relation['rules'] as $rule) { if (isset($rule['_value'])) { $match = $this->match($rule['_value'], $value); } else { if (!is_string($rule['value']) && !is_numeric($rule['value']) && !is_array($rule['value'])) { throw new Exception('Wrong value type in relations config "' . $rule['value'] . '"'); } $match = $this->match($rule['value'], $value); } if ($match) { if (!empty($rule['_elements'])) { $available = array_merge($available, $rule['_elements']); } } else { if (!empty($rule['_elements'])) { $unavailable = array_merge($unavailable, $rule['_elements']); } } } if ($unavailable) { $unavailable = array_diff($unavailable, $available); $unavailable = array_diff($unavailable, $this->_dfPreserveFields); /* should not set null for not-existed entries*/ $unavailable = array_intersect($unavailable, array_keys($values)); $values = array_merge($values, array_fill_keys($unavailable, null)); } } return; } /** * Converts relations config ready to use with jQuery.dynamicForm plugin * @return array */ public function dfConvertRelations() { $relations = []; foreach ($this->_dfRelations as $relation) { foreach ($relation['rules'] as &$rule) { if (!empty($rule['_elements'])) { foreach ($rule['_elements'] as $name) { if (($id = $this->_dfGetElementLabelId($name))) { $rule['nodes'][] = '#' . $id; } if (($id = $this->_dfGetElementContainerId($name))) { $rule['nodes'][] = '#' . $id; } } } unset($rule['_elements'], $rule['_value']); } unset($relation['_element']); $relations[] = $relation; } return $relations; } /** * @param $name * @return null|\Qs_Form_SubForm|\Zend_Form_DisplayGroup|\Zend_Form_Element */ public function getItem($name) { if (!($item = $this->getElement($name))) { if (!($item = $this->getDisplayGroup($name))) { if (!($item = $this->getSubForm($name))) { return null; } } } return $item; } /** * @param string $name Element/Display Group/Sub Form Name * @return string element label id (e.g. foo-label) */ protected function _dfGetElementLabelId($name) { if (($item = $this->getItem($name))) { return $item->getId() . '-label'; } return null; } /** * @param string $name element name * @return string element container id (e.g. foo-element) */ protected function _dfGetElementContainerId($name) { if (($item = $this->getItem($name))) { return $item->getId() . '-element'; } return null; } protected function _addResources() { $this->getDoc()->addScript('js/jquery.dynamicForm.js'); $this->getDoc()->addInitFunction( '$("#' . $this->getId() . '").dynamicForm', [['relations' => $this->dfConvertRelations()]] ); return parent::_addResources(); } protected function match($ruleValue, $targetValue) { if ($ruleValue instanceof \Closure) { return $ruleValue($targetValue); } if (is_array($ruleValue)) { return in_array($targetValue, $ruleValue); } return $ruleValue == $targetValue; } protected function isVisible($name) { foreach ($this->_dfRelations as $relation) { $value = $this->_getData($relation['element']); foreach ($relation['rules'] as $rule) { if (!$this->match($rule['value'], $value)) { continue; } if (in_array($name, $rule['_elements'])) { return true; } } } return false; } }