/** * Adds columns from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_TableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addBrowseTableColumns(\MUtil_Model_Bridge_TableBridge $bridge, \MUtil_Model_ModelAbstract $model) { if ($model->has('row_class')) { $bridge->getTable()->tbody()->getFirst(true)->appendAttrib('class', $bridge->row_class); } if ($editMenuItem = $this->getEditMenuItem()) { $bridge->addItemLink($editMenuItem->toActionLinkLower($this->request, $bridge)); } // make sure search results are highlighted $this->applyTextMarker(); if ($this->columns) { foreach ($this->columns as $column) { call_user_func_array(array($bridge, 'addMultiSort'), $column); } } elseif ($this->sortableLinks) { foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $bridge->addSortable($name, $label); } } } else { foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $bridge->add($name, $label); } } } if ($deleteMenuItem = $this->findMenuItem($this->request->getControllerName(), 'delete')) { $bridge->addItemLink($deleteMenuItem->toActionLinkLower($this->request, $bridge)); } }
/** * Handles creating or replacing the view for this survey * * @param \Gems_Tracker_Survey $viewName * @param \MUtil_Model_ModelAbstract $answerModel */ protected function replaceCreateView(\Gems_Tracker_Survey $survey, \MUtil_Model_ModelAbstract $answerModel) { $viewName = $this->getViewName($survey); $responseDb = $this->project->getResponseDatabase(); $fieldSql = ''; foreach ($answerModel->getItemsOrdered() as $name) { if (true === $answerModel->get($name, 'survey_question') && !in_array($name, array('submitdate', 'startdate', 'datestamp')) && !$answerModel->is($name, 'type', \MUtil_Model::TYPE_NOVALUE)) { // Only real answers $fieldSql .= ',MAX(IF(gdr_answer_id = ' . $responseDb->quote($name) . ', gdr_response, NULL)) AS ' . $responseDb->quoteIdentifier($name); } } if ($fieldSql > '') { $dbConfig = $this->db->getConfig(); $tokenTable = $this->db->quoteIdentifier($dbConfig['dbname'] . '.gems__tokens'); $createViewSql = 'CREATE OR REPLACE VIEW ' . $responseDb->quoteIdentifier($viewName) . ' AS SELECT gdr_id_token'; $createViewSql .= $fieldSql; $createViewSql .= "FROM gemsdata__responses join " . $tokenTable . " on (gto_id_token=gdr_id_token and gto_id_survey=" . $survey->getSurveyId() . ") GROUP BY gdr_id_token;"; try { $responseDb->query($createViewSql)->execute(); } catch (Exception $exc) { $responseConfig = $responseDb->getConfig(); $dbUser = $this->db->quoteIdentifier($responseConfig['username']) . '@' . $this->db->quoteIdentifier($responseConfig['host']); $statement = "GRANT SELECT ON " . $tokenTable . " TO " . $dbUser; $this->getBatch()->addMessage(sprintf($this->_("Creating view failed, try adding rights using the following statement: %s"), $statement)); } } }
/** * This function is called in addBrowseTableColumns() to filter the names displayed * by AnswerModelSnippetGeneric. * * @see \Gems_Tracker_Snippets_AnswerModelSnippetGeneric * * @param \MUtil_Model_Bridge_TableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @param array $currentNames The current names in use (allows chaining) * @return array Of the names of labels that should be shown */ public function filterAnswers(\MUtil_Model_Bridge_TableBridge $bridge, \MUtil_Model_ModelAbstract $model, array $currentNames) { $repeater = $model->loadRepeatable(); $table = $bridge->getTable(); $table->setRepeater($repeater); // Filter unless option 'fullanswers' is true, can be set as get or post var. $requestFullAnswers = \Zend_Controller_Front::getInstance()->getRequest()->getParam('fullanswers', false); if (!$repeater->__start()) { return $currentNames; } $keys = array(); if ($requestFullAnswers !== false) { // No filtering return $model->getItemsOrdered(); } else { foreach ($model->getItemNames() as $name) { $start = substr(strtolower($name), 0, $this->IncludeLength); if (in_array($start, $this->IncludeStarts)) { $keys[$name] = $name; } } } $answers = $this->token->getRawAnswers(); // Prevent errors when no answers present if (!empty($answers)) { $results = array_intersect($currentNames, array_keys($keys), array_keys($answers)); } else { $results = array_intersect($currentNames, array_keys($keys)); } $results = $this->restoreHeaderPositions($model, $results); if ($results) { return $results; } return $this->getHeaders($model, $currentNames); }
/** * Adds rows from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_VerticalTableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addShowTableRows(\MUtil_Model_Bridge_VerticalTableBridge $bridge, \MUtil_Model_ModelAbstract $model) { $items = $model->getItemsOrdered(); foreach ($items as $name) { if ($model->get($name, 'type') === \MUtil_Model::TYPE_CHILD_MODEL) { $this->submodel = $model->get($name, 'model'); $subitems = $this->submodel->getItemsOrdered(); } } if (isset($subitems) && is_array($subitems)) { $items = array_diff($items, $subitems); } foreach ($items as $name) { if ($label = $model->get($name, 'label')) { $bridge->addItem($name, $label); } } /*if ($subitems) { $bridge->addItem('gctt', 'moo'); }*/ if ($model->has('row_class')) { // Make sure deactivated rounds are show as deleted foreach ($bridge->getTable()->tbody() as $tr) { foreach ($tr as $td) { if ('td' === $td->tagName) { $td->appendAttrib('class', $bridge->row_class); } } } } }
/** * Adds rows from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_VerticalTableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addShowTableRows(\MUtil_Model_Bridge_VerticalTableBridge $bridge, \MUtil_Model_ModelAbstract $model) { foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $bridge->addItem($name, $label); } } if ($model->has('row_class')) { // Make sure deactivated rounds are show as deleted foreach ($bridge->getTable()->tbody() as $tr) { foreach ($tr as $td) { if ('td' === $td->tagName) { $td->appendAttrib('class', $bridge->row_class); } } } } }
/** * Adds columns from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_TableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addBrowseTableColumns(\MUtil_Model_Bridge_TableBridge $bridge, \MUtil_Model_ModelAbstract $model) { $br = \MUtil_Html::create('br'); if ($this->showSelected) { $selectedClass = \MUtil_Lazy::iff(\MUtil_Lazy::comp($bridge->gto_id_token, '==', $this->tokenId), 'selectedColumn', null); } else { $selectedClass = null; } $bridge->th($this->_('Status')); $td = $bridge->tdh(\MUtil_Lazy::first($bridge->grc_description, $this->_('OK'))); $td->appendAttrib('class', $selectedClass); $bridge->th($this->_('Question')); if ($model->has('grr_name') && $model->has('gtf_field_name')) { $td = $bridge->tdh(\MUtil_Lazy::iif($bridge->grr_name, array($bridge->grr_name, $br)), \MUtil_Lazy::iif($bridge->gtf_field_name, array($bridge->gtf_field_name, $br)), $bridge->gto_round_description, \MUtil_Lazy::iif($bridge->gto_round_description, $br), \MUtil_Lazy::iif($bridge->gto_completion_time, $bridge->gto_completion_time, $bridge->gto_valid_from)); } else { $td = $bridge->tdh($bridge->gto_round_description, \MUtil_Lazy::iif($bridge->gto_round_description, $br), \MUtil_Lazy::iif($bridge->gto_completion_time, $bridge->gto_completion_time, $bridge->gto_valid_from)); } $td->appendAttrib('class', $selectedClass); $td->appendAttrib('class', $bridge->row_class); // Apply filter on the answers displayed $answerNames = $model->getItemsOrdered(); if ($this->answerFilter instanceof \Gems_Tracker_Snippets_AnswerNameFilterInterface) { $answerNames = $this->answerFilter->filterAnswers($bridge, $model, $answerNames); } foreach ($answerNames as $name) { $label = $model->get($name, 'label'); if (null !== $label) { // Was strlen($label), but this ruled out empty sub-questions $bridge->thd($label, array('class' => $model->get($name, 'thClass'))); $td = $bridge->td($bridge->{$name}); $td->appendAttrib('class', 'answer'); $td->appendAttrib('class', $selectedClass); $td->appendAttrib('class', $bridge->row_class); } } $bridge->th($this->_('Token')); $tokenUpper = $bridge->gto_id_token->strtoupper(); if ($this->showTakeButton && ($menuItem = $this->menu->find(array('controller' => 'ask', 'action' => 'take', 'allowed' => true)))) { $source = new \Gems_Menu_ParameterSource(); $source->setTokenId($bridge->gto_id_token); $source->offsetSet('can_be_taken', $bridge->can_be_taken); $link = $menuItem->toActionLink($source); if ($link) { $link->title = array($this->_('Token'), $tokenUpper); } $td = $bridge->tdh($bridge->can_be_taken->if($link, $tokenUpper)); } else { $td = $bridge->tdh($tokenUpper); } $td->appendAttrib('class', $selectedClass); $td->appendAttrib('class', $bridge->row_class); }
/** * Returns an array with all columns from the model that have a label * * @param array $data * @param \MUtil_Model_ModelAbstract $model * @return array */ protected function getExcelData($data, \MUtil_Model_ModelAbstract $model) { $headings = array(); $emptyMsg = sprintf($this->_('No %s found.'), $this->getTopic(0)); foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $headings[$name] = (string) $label; } } $results = array(); $results[] = $headings; if ($headings) { if ($data) { foreach ($data as $row) { $results[] = array_intersect_key($row, $headings); } return $results; } else { $result = array(); foreach ($headings as $key => $value) { $result[$key] = $emptyMsg; } $results[] = $result; return $results; } } else { return array($emptyMsg); } }
/** * Adds columns from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_TableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addBrowseTableColumns(\MUtil_Model_Bridge_TableBridge $bridge, \MUtil_Model_ModelAbstract $model) { $tUtil = $this->util->getTokenData(); $table = $bridge->getTable(); $table->appendAttrib('class', 'compliance'); $thead = $table->thead(); $th_row = $thead->tr(array('class' => 'rounds')); $th = $th_row->td(); $span = 1; $cRound = null; $cDesc = null; $thead->tr(); if ($showMenuItem = $this->getShowMenuItem()) { $bridge->addItemLink($showMenuItem->toActionLinkLower($this->request, $bridge)); } // Initialize alter $alternateClass = new \MUtil_Lazy_Alternate(array('odd', 'even')); foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $round = $model->get($name, 'round'); if ($round == $cRound) { $span++; $class = null; } else { // If the round has an icon, show the icon else just 'R' since // complete round description messes up the display $th->append($cDesc); $th->title = $cRound; $th->colspan = $span; $span = 1; $cRound = $round; if ($cIcon = $model->get($name, 'roundIcon')) { $cDesc = \MUtil_Html_ImgElement::imgFile($cIcon, array('alt' => $cRound, 'title' => $cRound)); } else { if (substr($name, 0, 5) == 'stat_') { $cDesc = 'R'; } else { $cDesc = null; } } $class = 'newRound'; $thClass = $class . ' ' . $alternateClass; // Add alternate class only for th $th = $th_row->td(array('class' => $thClass)); } if ($model->get($name, 'noSort')) { $title = array(\MUtil_Lazy::method($tUtil, 'getStatusDescription', $bridge->{$name}), "\n" . $model->get($name, 'description')); $token = 'tok_' . substr($name, 5); $href = new \MUtil_Html_HrefArrayAttribute(array($this->request->getControllerKey() => 'track', $this->request->getActionKey() => 'show', \MUtil_Model::REQUEST_ID => $bridge->{$token})); $href->setRouteReset(); $onclick = new \MUtil_Html_OnClickArrayAttribute(); $onclick->addUrl($href)->addCancelBubble(); $tds = $bridge->addColumn(array(\MUtil_Html_AElement::iflink($bridge->{$token}, array($href, 'onclick' => 'event.cancelBubble = true;', 'title' => $title, $bridge->{$name}), $bridge->{$name}), 'class' => array('round', \MUtil_Lazy::method($tUtil, 'getStatusClass', $bridge->{$name})), 'title' => $title, 'onclick' => \MUtil_Lazy::iff($bridge->{$token}, $onclick)), array($label, 'title' => $model->get($name, 'description'), 'class' => 'round')); } else { $tds = $bridge->addSortable($name, $label); } if ($class) { $tds->appendAttrib('class', $class); } } } $th->append($cRound); $th->colspan = $span; }
/** * Adds columns from the model to the bridge that creates the browse table. * * Overrule this function to add different columns to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_TableBridge $bridge * @param \MUtil_Model_ModelAbstract $model * @return void */ protected function addBrowseTableColumns(\MUtil_Model_Bridge_TableBridge $bridge, \MUtil_Model_ModelAbstract $model) { if ($this->columns) { foreach ($this->columns as $column) { call_user_func_array(array($bridge, 'addMultiSort'), $column); } } elseif ($this->sortableLinks) { foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $bridge->addSortable($name, $label); } } } else { foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $bridge->add($name, $label); } } } }
/** * Add an extra model to the union * * @param \MUtil_Model_ModelAbstract $model * @param array $fieldMap Map from the sub model field names to this models names * @param string $name * @return \MUtil_Model_UnionModelAbstract (continuation pattern) */ public function addUnionModel(\MUtil_Model_ModelAbstract $model, array $fieldMap = null, $name = null) { if (null === $name) { $name = $model->getName(); } $this->_unionModels[$name] = $model; if ($fieldMap) { $this->_unionMapsFrom[$name] = $fieldMap; $this->_unionMapsTo[$name] = array_flip($fieldMap); } else { $this->_unionMapsFrom[$name] = false; $this->_unionMapsTo[$name] = false; $fieldMap = array(); } foreach ($model->getItemsOrdered() as $subName) { if (isset($fieldMap[$subName])) { $mainName = $fieldMap[$subName]; } else { $mainName = $subName; } $this->set($mainName, $model->get($subName)); } return $this; }
/** * Returns an array with all columns from the model that have a label * * @param array $data * @param \MUtil_Model_ModelAbstract $model * @return array */ protected function getExcelData($data, \MUtil_Model_ModelAbstract $model) { $headings = array(); $emptyMsg = $this->_('No data found.'); foreach ($model->getItemsOrdered() as $name) { if ($label = $model->get($name, 'label')) { $headings[$name] = (string) $label; } } $results = array(); $results[] = $headings; if ($headings) { if ($data) { foreach ($data as $row) { foreach ($headings as $key => $value) { $result[$key] = isset($row[$key]) ? $row[$key] : null; } $results[] = $result; } return $results; } else { foreach ($headings as $key => $value) { $result[$key] = $emptyMsg; } $results[] = $result; return $results; } } else { return array($emptyMsg); } }
/** * Adds elements from the model to the bridge that creates the form. * * Overrule this function to add different elements to the browse table, without * having to recode the core table building code. * * @param \MUtil_Model_Bridge_FormBridgeInterface $bridge * @param \MUtil_Model_ModelAbstract $model * @param array $data The data that will later be loaded into the form * @param optional boolean $new Form should be for a new element * @return void|array When an array of new values is return, these are used to update the $data array in the calling function */ protected function addFormElements(\MUtil_Model_Bridge_FormBridgeInterface $bridge, \MUtil_Model_ModelAbstract $model, array $data, $new = false) { foreach ($model->getItemsOrdered() as $name) { if ($model->has($name, 'label') || $model->has($name, 'elementClass')) { $bridge->add($name); } else { $bridge->addHidden($name); } } }
/** * Get the descriptions of the translators * * @param mixed $for A single translator, an array of translators or all translators if null; * @return array key -> description */ protected function getTranslatorTable($for = null) { if (!$this->targetModel) { return array(); } if (null === $for) { $for = $this->getTranslatorDescriptions(); } elseif (!is_array($for)) { $descriptors = $this->getTranslatorDescriptions(); if (!isset($descriptors[$for])) { throw new \Zend_Exception("Unknown translator {$for} passed to " . __CLASS__ . '->' . __FUNCTION__ . '()'); } $for = array($for => $descriptors[$for]); } $requiredKey = $this->_('Required'); $minimal = array($requiredKey => ' '); // Array for making sure all fields are there $results = array_fill_keys($this->targetModel->getItemsOrdered(), array()); $transCount = count($for); foreach ($for as $transKey => $transName) { if (!isset($this->importTranslators[$transKey])) { throw new \Zend_Exception("Unknown translator {$for} passed to " . __CLASS__ . '->' . __FUNCTION__ . '()'); } $translator = $this->importTranslators[$transKey]; if ($translator instanceof \MUtil_Model_ModelTranslatorInterface) { $translator->setTargetModel($this->targetModel); $translations = $translator->getFieldsTranslations(); $requireds = $translator->getRequiredFields(); $minimal[$transName] = ' '; foreach ($translations as $source => $target) { // Skip numeric fields if (!is_int($source)) { $required = isset($requireds[$source]); // Add required row $results[$target][$requiredKey][$transName] = $required; if (trim($required)) { $results[$target][$transName] = new \MUtil_Html_HtmlElement('strong', $source); } else { $results[$target][$transName] = $source; } } } } } $output = array(); foreach ($results as $name => $resultRow) { if (count($resultRow) > 1) { // Always first $requireds = count(array_filter($resultRow[$requiredKey])); $resultRow[$requiredKey] = $requireds ? $requireds == $transCount ? $this->_('Yes') : $this->_('For bold') : ' '; if ($this->targetModel->has($name, 'label')) { $label = $this->targetModel->get($name, 'label'); } else { $label = $name; } // $field = $this->_targetModel->get($name, 'type', 'maxlength', 'label', 'required'); switch ($this->targetModel->get($name, 'type')) { case \MUtil_Model::TYPE_NOVALUE: unset($results[$name]); continue 2; case \MUtil_Model::TYPE_NUMERIC: $maxlength = $this->targetModel->get($name, 'maxlength'); if ($maxlength) { $decimals = $this->targetModel->get($name, 'decimals'); if ($decimals) { $type = sprintf($this->_('A number of length %d, with a precision of %d digits after the period.'), $maxlength, $decimals); } else { $type = sprintf($this->_('A whole number of length %d.'), $maxlength); } } else { $type = $this->_('A numeric value'); } break; case \MUtil_Model::TYPE_DATE: $type = $this->_('Date value using ISO 8601: yyyy-mm-dd'); break; case \MUtil_Model::TYPE_DATETIME: $type = $this->_('Datetime value using ISO 8601: yyyy-mm-ddThh:mm::ss[+-hh:mm]'); break; case \MUtil_Model::TYPE_TIME: $type = $this->_('Time value using ISO 8601: hh:mm::ss[+-hh:mm]'); break; default: $maxlength = $this->targetModel->get($name, 'maxlength'); $minlength = $this->targetModel->get($name, 'minlength'); if ($maxlength && $minlength) { $type = sprintf($this->plural('Text, between %d and %d character', 'Text, between %d and %d characters', $maxlength), $minlength, $maxlength); } elseif ($maxlength) { $type = sprintf($this->plural('Text, %d character', 'Text, %d characters', $maxlength), $maxlength); } elseif ($minlength) { $type = sprintf($this->plural('Text, at least %d character', 'Text, at least %d characters', $minlength), $minlength); } else { $type = $this->_('Text'); } break; } $options = $this->targetModel->get($name, 'multiOptions'); if ($options) { $cutoff = 6; $i = 0; $optionDescr = ''; $separator = $this->_(', '); if (is_callable($options)) { $options = call_user_func($options); } foreach ($options as $key => $value) { $optionDescr .= $separator . $key; $i++; if ($key != $value) { $optionDescr .= sprintf($this->_(', %s'), $value); $i++; } if ($i > $cutoff) { break; } } $optionDescr = substr($optionDescr, strlen($separator)); if ($i < $cutoff) { // $type .= $this->_('; one of: ') . implode($this->_(', '), array_keys($options)); $type .= sprintf($this->_('; one of: %s'), $optionDescr); } else { $type .= sprintf($this->_('; e.g. one of: %s, ...'), $optionDescr); } } $typeDescr = $this->targetModel->get($name, 'import_descr'); if ($typeDescr) { $type .= $this->_('; ') . $typeDescr; } $resultRow[$this->_('Field description')] = (string) $label ? $label : $this->_('<<no description>>'); $resultRow[$this->_('Content')] = $type; // Make sure all fields are there $resultRow = array_merge($minimal, $resultRow); $output[$name] = $resultRow; } } uksort($output, array($this, '_sortTranslatorTable')); return $output; }