/** * Allows the loader to set resources. * * @param string $name Name of resource to set * @param mixed $resource The resource. * @return boolean True if $resource was OK */ public function answerRegistryRequest($name, $resource) { if (\MUtil_Registry_Source::$verbose) { \MUtil_Echo::r('Resource set: ' . get_class($this) . '->' . __FUNCTION__ . '("' . $name . '", ' . (is_object($resource) ? get_class($resource) : gettype($resource)) . ')'); } $this->{$name} = $resource; return true; }
/** * Instantiate a new class using the arguments array for initiation * * @param string $className * @param array $arguments Instanciation arguments * @return className */ public function createClass($className, array $arguments = array()) { $object = parent::createClass($className, $arguments); if ($object instanceof \MUtil_Registry_TargetInterface) { if ($this->_source instanceof \MUtil_Registry_SourceInterface) { $this->_source->applySource($object); } elseif (self::$verbose) { \MUtil_Echo::r("Loading target class {$className}, but source not set."); } } return $object; }
/** * Stores the fields that can be used for sorting or filtering in the * sort / filter objects attached to this model. * * @param array $parameters * @param boolean $includeNumericFilters When true numeric filter keys (0, 1, 2...) are added to the filter as well * @return array The $parameters minus the sort & textsearch keys */ public function applyParameters(array $parameters, $includeNumericFilters = false) { if ($parameters) { // Allow use when passed only an ID value if (isset($parameters[\MUtil_Model::REQUEST_ID]) && !isset($parameters[\MUtil_Model::REQUEST_ID1], $parameters[\MUtil_Model::REQUEST_ID2])) { $id = $parameters[\MUtil_Model::REQUEST_ID]; $keys = $this->getKeys(); $field = array_shift($keys); $parameters[$field] = $id; if ($field2 = array_shift($keys)) { $parameters[$field2] = $this->getCurrentOrganization(); \MUtil_Echo::r('Still using old HiddenModel parameters.', 'DEPRECIATION WARNING'); \MUtil_Echo::r($parameters); } unset($parameters[\MUtil_Model::REQUEST_ID]); } if (isset($parameters[\MUtil_Model::REQUEST_ID2]) && !array_key_exists($parameters[\MUtil_Model::REQUEST_ID2], $this->currentUser->getAllowedOrganizations())) { $this->initTranslateable(); throw new \Gems_Exception($this->_('Inaccessible or unknown organization'), 403, null, sprintf($this->_('Access to this page is not allowed for current role: %s.'), $this->currentUser->getRole())); } return parent::applyParameters($parameters, $includeNumericFilters); } return array(); }
/** * Survey dependent calculations / answer changes that must occur after a survey is completed * * @param type $tokenId The tokend the answers are for * @param array $tokenAnswers Array with answers. May be changed in process * @return array The changed values */ public function handleBeforeAnswering() { $survey = $this->getSurvey(); $event = $survey->getSurveyBeforeAnsweringEvent(); if ($event) { try { $changed = $event->processTokenInsertion($this); if ($changed && is_array($changed)) { $this->setRawAnswers($changed); if (\Gems_Tracker::$verbose) { \MUtil_Echo::r($changed, 'Source values for ' . $this->_tokenId . ' changed by event.'); } return $changed; } } catch (\Exception $e) { $this->logger->log(sprintf("Before answering event error for token %s on survey '%s' using event '%s': %s", $this->_tokenId, $this->getSurveyName(), $event->getEventName(), $e->getMessage()), \Zend_Log::ERR); } } }
/** * Returns a field from the raw answers as a date object. * * A seperate function as only the source knows what format the date/time value has. * * @param string $fieldName Name of answer field * @param \Gems_Tracker_Token $token Gems token object * @param int $surveyId Gems Survey Id * @param string $sourceSurveyId Optional Survey Id used by source * @return \MUtil_Date date time or null */ public function getAnswerDateTime($fieldName, \Gems_Tracker_Token $token, $surveyId, $sourceSurveyId = null) { $answers = $token->getRawAnswers(); if (isset($answers[$fieldName]) && $answers[$fieldName]) { if (\Zend_Date::isDate($answers[$fieldName], \Zend_Date::ISO_8601)) { return new \MUtil_Date($answers[$fieldName], \Zend_Date::ISO_8601); } if (\Gems_Tracker::$verbose) { \MUtil_Echo::r($answers[$fieldName], 'Missed answer date value:'); } } }
/** * Send a warning, if not already done * * @staticvar boolean $warn */ private function _warn() { static $warn = true; if ($warn) { \MUtil_Echo::r('Database needs to be updated, tables missing!'); $warn = false; } }
/** * Searches and loads a .php snippet file. * * @param string $filename The name of the snippet * @param array $extraSourceParameters name/value pairs to add to the source for this snippet * @return \MUtil_Snippets_SnippetInterface The snippet */ public function getSnippet($filename, array $extraSourceParameters = null) { try { $this->addRegistryContainer($extraSourceParameters, 'tmpContainer'); $snippet = $this->_loadClass($filename, true); $this->removeRegistryContainer('tmpContainer'); if (self::$verbose) { \MUtil_Echo::r('Loading snippet ' . $filename . '<br/>' . 'Using snippet: ' . get_class($snippet)); } } catch (\Exception $exc) { if (self::$verbose) { \MUtil_Echo::r($exc->getMessage(), __CLASS__ . '->' . __FUNCTION__ . '(' . $filename . ')'); } throw $exc; } return $snippet; }
/** * Save a single model item. * * @param array $newValues The values to store for a single model item. * @param array $filter If the filter contains old key values these are used * to decide on update versus insert. * @param array $saveTables Optional array containing the table names to save, * otherwise the tables set to save at model level will be saved. * @return array The values as they are after saving (they may change). */ protected function _save(array $newValues, array $filter = null, array $saveTables = null) { $saveTables = $this->_checkSaveTables($saveTables); $oldChanged = $this->getChanged(); // \MUtil_Echo::track($newValues, $filter, $saveTables, $this->_joinFields); $oldValues = $newValues; foreach ($saveTables as $tableName => $saveMode) { // Gotta repeat this every time, as keys may be set later foreach ($this->_joinFields as $source => $target) { // Use is_string as $target and $target can be e.g. a \Zend_Db_Expr() object // as $source is an index keys it must be a string if (is_string($target)) { if (!(isset($newValues[$target]) && $newValues[$target])) { if (!(isset($newValues[$source]) && $newValues[$source])) { if (\MUtil_Model::$verbose) { \MUtil_Echo::r('Missing: ' . $source . ' -> ' . $target, 'ERROR!'); } continue; } $newValues[$target] = $newValues[$source]; } elseif (!(isset($newValues[$source]) && $newValues[$source])) { $newValues[$source] = $newValues[$target]; } elseif (strlen($newValues[$target]) > 0 && strlen($newValues[$source]) > 0 && $newValues[$target] != $newValues[$source]) { // Join key values changed. // // Set the old values as the filter $filter[$target] = $newValues[$target]; $filter[$source] = $newValues[$source]; // Switch the target value to the value in the source field. // // JOIN FIELD ORDER IS IMPORTANT!!! // The changing field must be stated first in the join statement. $newValues[$target] = $newValues[$source]; } } elseif ($target instanceof \Zend_Db_Expr && !(isset($newValues[$source]) && $newValues[$source])) { $newValues[$source] = $target; } } //$this->_saveTableData returns the new row values, including any automatic changes. $newValues = $this->_saveTableData($this->_tables[$tableName], $newValues, $filter, $saveMode) + $oldValues; // \MUtil_Echo::track($oldValues, $newValues, $filter); $oldValues = $newValues; } // If anything has changed, it counts as only one item for the user. if ($this->getChanged() > $oldChanged) { $this->setChanged(++$oldChanged); } return $newValues; }
/** * General utility function for saving a row in a table. * * This functions checks for prior existence of the row and switches * between insert and update as needed. Key updates can be handled through * passing the $oldKeys or by using copyKeys(). * * @see copyKeys() * * @param \Zend_Db_Table_Abstract $table The table to save * @param array $newValues The values to save, including those for other tables * @param array $oldKeys The original keys as they where before the changes * @param int $saveMode Should updates / inserts occur * @return array The values for this table as they were updated */ protected function _saveTableData(\Zend_Db_Table_Abstract $table, array $newValues, array $oldKeys = null, $saveMode = self::SAVE_MODE_ALL) { if (!$newValues) { return array(); } $tableName = $this->_getTableName($table); $primaryKeys = $this->_getKeysFor($tableName); $primaryCount = count($primaryKeys); $filter = array(); $update = true; // \MUtil_Echo::r($newValues, $tableName); foreach ($primaryKeys as $key) { if (array_key_exists($key, $newValues) && 0 == strlen($newValues[$key])) { // Never include null key values, except when we have a save transformer if (!$this->has($key, self::SAVE_TRANSFORMER)) { unset($newValues[$key]); if (\MUtil_Model::$verbose) { \MUtil_Echo::r('Null key value: ' . $key, 'INSERT!!'); } } // Now we know we are not updating $update = false; } elseif (isset($oldKeys[$key])) { if (\MUtil_Model::$verbose) { \MUtil_Echo::r($key . ' => ' . $oldKeys[$key], 'Old key'); } $filter[$key . ' = ?'] = $oldKeys[$key]; // Key values left in $returnValues in case of partial key insert } else { // Check for old key values being stored using copyKeys() $copyKey = $this->getKeyCopyName($key); if (isset($newValues[$copyKey])) { $filter[$key . ' = ?'] = $newValues[$copyKey]; if (\MUtil_Model::$verbose) { \MUtil_Echo::r($key . ' => ' . $newValues[$copyKey], 'Copy key'); } } elseif (isset($newValues[$key])) { $filter[$key . ' = ?'] = $newValues[$key]; if (\MUtil_Model::$verbose) { \MUtil_Echo::r($key . ' => ' . $newValues[$key], 'Key'); } } } } if (!$filter) { $update = false; } if ($update) { // \MUtil_Echo::r($filter, 'Filter'); $adapter = $this->getAdapter(); $wheres = array(); foreach ($filter as $text => $value) { $wheres[] = $adapter->quoteInto($text, $value); } // Retrieve the record from the database $oldValues = $table->fetchRow('(' . implode(' ) AND (', $wheres) . ')'); if (!$oldValues) { // \MUtil_Echo::r('INSERT!!', 'Old not found'); // Apparently the record does not exist in the database $update = false; } else { $oldValues = $oldValues->toArray(); } } // Check for actual values for this table to save. // \MUtil_Echo::track($newValues); if ($returnValues = $this->_filterDataFor($tableName, $newValues, !$update)) { if (\MUtil_Model::$verbose) { \MUtil_Echo::r($returnValues, 'Return'); } // \MUtil_Echo::track($returnValues); if ($update) { // \MUtil_Echo::r($filter); // Check for actual changes foreach ($oldValues as $name => $value) { // The name is in the set being stored if (array_key_exists($name, $returnValues)) { if ($this->isAutoSave($name)) { continue; } if (is_object($returnValues[$name]) || is_object($value)) { $noChange = $returnValues[$name] == $value; } else { // Make sure differences such as extra start zero's on text fields do // not disappear, while preventing a difference between an integer // and string input of triggering a false change $noChange = $returnValues[$name] == $value && strlen($returnValues[$name]) == strlen($value); } // Detect change that is not auto update if (!$noChange) { // \MUtil_Echo::track($name, $returnValues[$name], $value); // \MUtil_Echo::track($returnValues); // Update the row, if the saveMode allows it if ($saveMode & self::SAVE_MODE_UPDATE && ($changed = $table->update($returnValues, $filter))) { $this->addChanged($changed); // Make sure the copy keys (if any) have the new values as well $returnValues = $this->_updateCopyKeys($primaryKeys, $returnValues); // Add the old values as we have them and they may be of use later on. $returnValues = $returnValues + $oldValues; return $returnValues; } } } } // Add the old values as we have them and they may be of use later on. return $returnValues + $oldValues; } elseif ($saveMode & self::SAVE_MODE_INSERT) { // Perform insert // \MUtil_Echo::r($returnValues); $newKeyValues = $table->insert($returnValues); $this->addChanged(); // \MUtil_Echo::rs($newKeyValues, $primaryKeys); // Composite key returned. if (is_array($newKeyValues)) { foreach ($newKeyValues as $key => $value) { $returnValues[$key] = $value; } return $this->_updateCopyKeys($primaryKeys, $returnValues); } else { // Single key returned foreach ($primaryKeys as $key) { // Fill the first empty value if (!isset($returnValues[$key])) { $returnValues[$key] = $newKeyValues; return $this->_updateCopyKeys($primaryKeys, $returnValues); } } // But if all the key values were already filled, make sure the new values are returned. return $this->_updateCopyKeys($primaryKeys, $returnValues); } } } return array(); }
/** * Searches for a matching image location and returns that location when found. * * $filenames starting with a '/' or with http or https are skipped. * * @param type $filename The src attribute as filename * @return string When a directory matches */ public static function getImageDir($filename) { if ($filename && '/' != $filename[0] && 'http://' != substr($filename, 0, 7) && 'https://' != substr($filename, 0, 8)) { $webRoot = self::getWebRoot(); foreach (self::$_imageDirs as $dir) { if (file_exists($webRoot . $dir . $filename)) { return $dir; } } if (\MUtil_Html::$verbose) { \MUtil_Echo::r("File not found: {$filename}. \n\nLooked in: \n" . implode(", \n", self::$_imageDirs)); } } }
/** * A function that determines the parameters that this menu item should have using these paramter * sources. * * @param \Gems_Menu_ParameterCollector $source A source of parameter values * @param array $parameters A usually empty array of parameters that is filled from the sources * @param boolean $raiseConditions When true, no lazyness is returned * @return boolean Or lazy condition. When true menu item is enabled otherwise false */ private function _applyParameterSources(\Gems_Menu_ParameterCollector $source, array &$parameters, $raiseConditions) { // \Gems_Menu::$verbose = true; // \MUtil_Echo::r($this->get('label')); $condition = true; if ($this->_applyParameterFilter($source, $raiseConditions, $condition)) { return false; } $this->_applyParameterSource($source, $parameters); // Test required parameters if ($this->_requiredParameters) { foreach ($this->_requiredParameters as $param => $name) { if (!isset($parameters[$param])) { if (\Gems_Menu::$verbose) { // \MUtil_Echo::backtrace(); \MUtil_Echo::r('<b>Not found:</b> ' . $param . '/' . $name, $this->get('label') . ' (' . $this->get('controller') . '/' . $this->get('action') . ')'); } return false; } } } if ($this->_hiddenOrgId && $raiseConditions) { // Remove org paramter that should remain hidden when conditions have been raised. if (isset($parameters[\MUtil_Model::REQUEST_ID1], $parameters[\MUtil_Model::REQUEST_ID2]) && $parameters[\MUtil_Model::REQUEST_ID2] == $this->_hiddenOrgId) { $parameters[\MUtil_Model::REQUEST_ID] = $parameters[\MUtil_Model::REQUEST_ID1]; unset($parameters[\MUtil_Model::REQUEST_ID1], $parameters[\MUtil_Model::REQUEST_ID2]); } } return $condition; }
/** * Returns the options from the allowedoptions array, using the supplied options first and trying * to find the missing ones in the model. * * @param string $name * @param array $options * @param array $allowedOptionKeys_array * @return array */ private function _mergeOptions($name, array $options, $allowedOptionKeys_array) { $args = func_get_args(); $allowedOptionsKeys = \MUtil_Ra::args($args, 2); $allowedOptions = array(); foreach ($allowedOptionsKeys as $allowedOptionsKey) { if (is_array($allowedOptionsKey)) { $allowedOptions = array_merge($allowedOptions, $allowedOptionsKey); } else { if (array_key_exists($allowedOptionsKey, $this->_allowedOptions)) { $allowedOptions = array_merge($allowedOptions, $this->_allowedOptions[$allowedOptionsKey]); } else { $allowedOptions[] = $allowedOptionsKey; } } } //If not explicitly set, use the form value for translatorDisabled, since we //create the element outside the form scope and later add it if (!isset($options['disableTranslator']) && array_search('disableTranslator', $allowedOptions) !== false) { $options['disableTranslator'] = $this->form->translatorIsDisabled(); } // Move options to model. if (isset($options['validator'])) { $this->model->set($name, 'validators[]', $options['validator']); unset($options['validator']); } if ($allowedOptions) { // Remove options already filled. Using simple array addition // might trigger a lot of lazy calculations that are not needed. $allowedOptionsFlipped = array_flip($allowedOptions); // First strip the options that are not allowed if (\MUtil_Model::$verbose) { $strippedKeys = array_keys(array_diff_key($options, $allowedOptionsFlipped)); if (!empty($strippedKeys)) { \MUtil_Echo::r($strippedKeys, 'stripped from options for ' . $name); } } $options = array_intersect_key($options, $allowedOptionsFlipped); // Now get allowed options from the model $modelOptions = $this->model->get($name, $allowedOptions); // Merge them: first use supplied $options, and add missing values from model return (array) $options + (array) $modelOptions; } return $options; }
/** * Hook 6: Called after \Zend_Controller_Router has determined the route set by the request. * * This events enables you to adjust the route after the routing has run it's course. * * Not initialized is the $controller object. * * Previous hook: routeStartup() * Actions since: $router->route() * Actions after: nothing, but the route consisting of controller, action and module should now be fixed * Next hook: dispatchLoopStartup() * * Also sets $this->currentOrganization and $this->menu to access afterwards * * @param \Zend_Controller_Request_Abstract $request * @return void */ public function routeShutdown(\Zend_Controller_Request_Abstract $request) { $loader = $this->getLoader(); // Load the menu. As building the menu can depend on all resources and the request, we do it here. // // PS: The REQUEST is needed because otherwise the locale for translate is not certain. $menu = $loader->createMenu($this); $source = $menu->getParameterSource(); $user = $this->_container->currentUser; $user->setRequest($request); $organization = $user->getCurrentOrganization(); $organization->applyToMenuSource($source); $this->_container->currentOrganization = $organization; $this->_container->menu = $menu; $this->_updateVariable(array('currentOrganization', 'menu')); // Now is a good time to check for required values // Moved down here to prevent unit test from failing on missing salt $this->project->checkRequiredValues(); /** * Check if we are in maintenance mode or not. This is triggeren by a file in the var/settings * directory with the name lock.txt */ if ($this->getUtil()->getMaintenanceLock()->isLocked()) { if ($user->isActive() && !$user->hasPrivilege('pr.maintenance.maintenance-mode')) { //Still allow logoff so we can relogin as master if (!('index' == $request->getControllerName() && 'logoff' == $request->getActionName())) { $this->setError($this->_('Please check back later.'), 401, $this->_('System is in maintenance mode')); } $user->unsetAsCurrentUser(); } else { $this->addMessage($this->_('System is in maintenance mode')); \MUtil_Echo::r($this->_('System is in maintenance mode')); } } // Gems does not use index/index $action = $request->getActionName(); if ('index' == $request->getControllerName() && ('index' == $action || $user->isActive() && 'login' == $action)) { // Instead Gems routes to the first available menu item when this is the request target if (!$user->gotoStartPage($menu, $request)) { $this->setError($this->_('No access to site.'), 401, $this->_('You have no access to this site.'), true); return; } } else { //find first allowed item in the menu $menuItem = $menu->find(array('action' => $request->getActionName(), 'controller' => $request->getControllerName())); // Display error when not having the right priviliges if (!($menuItem && $menuItem->get('allowed'))) { // When logged in if ($user->getUserId()) { $this->setError($this->_('No access to page'), 403, sprintf($this->_('Access to the %s/%s page is not allowed for current role: %s.'), $request->getControllerName(), $request->getActionName(), $user->getRole()), true); } else { // No longer logged in if (\MUtil_Console::isConsole()) { $this->setError('No access to page.', 401, sprintf('Controller "%s" action "%s" is not accessible.', $request->getControllerName(), $request->getActionName()), true); return; } if ($request->getActionName() == 'autofilter') { // Throw an exception + HTTP 401 when an autofilter is called throw new \Gems_Exception("Session expired", 401); } $menuItem = $menu->findFirst(array('allowed' => true, 'visible' => true)); if ($menuItem) { // Do not store previous request & show message when the intended action is logoff if (!($request->getControllerName() == 'index' && $request->getActionName() == 'logoff')) { $this->addMessage($this->_('You are no longer logged in.')); $this->addMessage($this->_('You must login to access this page.')); if (!\MUtil_String::contains($request->getControllerName() . $request->getActionName(), '.')) { // save original request, we will redirect back once the user succesfully logs in $staticSession = $this->getStaticSession(); $staticSession->previousRequestParameters = $request->getParams(); $staticSession->previousRequestMode = $request->isPost() ? "POST" : "GET"; } } $redirector = \Zend_Controller_Action_HelperBroker::getStaticHelper('redirector'); $redirector->gotoRoute($menuItem->toRouteUrl($request)); } else { $this->setError($this->_('You are no longer logged in.'), 401, $this->_('You have no access to this site.'), true); return; } } } } if (isset($menuItem)) { $menuItem->applyHiddenParameters($request, $source); $menu->setCurrent($menuItem); } }
/** * Renders the $content so that it can be used as output for the $view, * including output escaping and encoding correction. * * This functions handles \MUtil_Html_HtmlInterface and \MUtil_Lazy_LazyInterface * objects natively, as well as array, scalar values and objects with a * __toString function. * * Other objects a definition should have a render function in getClassRenderList(). * * All Lazy variabables are raised. * * @param \Zend_View_Abstract $view * @param mixed $content Anything HtmlInterface, number, string, array, object with __toString * or an object that has a defined render function in getClassRenderList(). * @return string Output to echo to the user */ public function renderArray(\Zend_View_Abstract $view, $content, $glue = '', $stack = null) { // \MUtil_Echo::timeFunctionStart(__FUNCTION__); $output = array(); // \MUtil_Echo::countOccurences('render'); foreach ($content as $key => $value) { // Resolve first as this function as recursion heavy enough as it is. if ($value instanceof \MUtil_Lazy_LazyInterface) { if (!$stack) { $stack = \MUtil_Lazy::getStack(); } // \MUtil_Echo::countOccurences('lazyIf'); while ($value instanceof \MUtil_Lazy_LazyInterface) { // \MUtil_Echo::countOccurences('lazyWhile'); $value = $value->__toValue($stack); } } if (is_scalar($value)) { // \MUtil_Echo::countOccurences('scalar'); // \MUtil_Echo::timeFunctionStart('escape2'); $output[$key] = $view->escape((string) $value); // \MUtil_Echo::timeFunctionStop('escape2'); } elseif ($value instanceof \MUtil_Html_HtmlInterface) { // \MUtil_Echo::countOccurences('interface'); $output[$key] = $value->render($view); } elseif (null === $value) { // \MUtil_Echo::countOccurences('null'); } elseif (is_array($value)) { // \MUtil_Echo::countOccurences('array'); $output[$key] = self::renderAny($view, $value, '', $stack); } elseif (is_object($value)) { $function = $this->_classRenderFunctions->get($value); if ($function) { // \MUtil_Echo::countOccurences('function'); $output[$key] = call_user_func($function, $view, $value); } elseif (method_exists($value, '__toString')) { // \MUtil_Echo::countOccurences('toString'); // \MUtil_Echo::countOccurences('toString.' . get_class($value)); $output[$key] = $view->escape($value->__toString()); } else { // $output[$key] = 'WARNING: Object of type ' . get_class($value) . ' cannot be converted to string.'; throw new \MUtil_Html_HtmlException('WARNING: Object of type ' . get_class($value) . ' cannot be converted to string.'); } } elseif ($value instanceof \__PHP_Incomplete_Class) { \MUtil_Echo::r($value, __CLASS__ . '->' . __FUNCTION__); $output[$key] = ''; } else { // Mop up, should not occur // \MUtil_Echo::countOccurences('scalar else'); $output[$key] = $view->escape((string) $value); } } if (false === $glue || null === $glue) { // \MUtil_Echo::timeFunctionStop(__FUNCTION__); return $output; } $output = implode($glue, $output); // \MUtil_Echo::timeFunctionStop(__FUNCTION__); return $output; }
/** * The transform function performs the actual transformation of the data and is called after * the loading of the data in the source model. * * @param \MUtil_Model_ModelAbstract $model The parent model * @param array $data Nested array * @param boolean $new True when loading a new item * @param boolean $isPostData With post data, unselected multiOptions values are not set so should be added * @return array Nested array containing (optionally) transformed data */ public function transformLoad(\MUtil_Model_ModelAbstract $model, array $data, $new = false, $isPostData = false) { if (!$data) { return $data; } //* $row = reset($data); if (!$this->crossTabs) { return $data; } $keys = $model->getKeys(); $keys = array_combine($keys, $keys); $default = array_fill_keys(array_keys(array_diff_key($this->_fields, $this->excludes)), null); $results = array(); // \MUtil_Echo::track($default); foreach ($data as $row) { foreach ($this->crossTabs as $crossTab) { $name = $crossTab['pre'] . $row[$crossTab['id']]; $key = implode("\t", array_intersect_key($row, $keys)); if (!isset($results[$key])) { $results[$key] = array_diff_key($row, $this->excludes) + $default; } $results[$key][$name] = $row[$crossTab['val']]; } } if (\MUtil_Model::$verbose) { \MUtil_Echo::r($results, 'Transform output'); } return $results; }
/** * Update the survey, both in the database and in memory. * * @param array $values The values that this token should be set to * @param int $userId The current user * @return int 1 if data changed, 0 otherwise */ private function _updateSurvey(array $values, $userId) { if ($this->tracker->filterChangesOnly($this->_gemsSurvey, $values)) { if (\Gems_Tracker::$verbose) { $echo = ''; foreach ($values as $key => $val) { $old = isset($this->_gemsSurvey[$key]) ? $this->_gemsSurvey[$key] : null; $echo .= $key . ': ' . $old . ' => ' . $val . "\n"; } \MUtil_Echo::r($echo, 'Updated values for ' . $this->_surveyId); } if (!isset($values['gsu_changed'])) { $values['gsu_changed'] = new \MUtil_Db_Expr_CurrentTimestamp(); } if (!isset($values['gsu_changed_by'])) { $values['gsu_changed_by'] = $userId; } if ($this->exists) { // Update values in this object $this->_gemsSurvey = $values + $this->_gemsSurvey; // return 1; return $this->db->update('gems__surveys', $values, array('gsu_id_survey = ?' => $this->_surveyId)); } else { if (!isset($values['gsu_created'])) { $values['gsu_created'] = new \MUtil_Db_Expr_CurrentTimestamp(); } if (!isset($values['gsu_created_by'])) { $values['gsu_created_by'] = $userId; } // Update values in this object $this->_gemsSurvey = $values + $this->_gemsSurvey; // Remove the Gems survey id unset($this->_gemsSurvey['gsu_id_survey']); $this->_surveyId = $this->db->insert('gems__surveys', $this->_gemsSurvey); $this->_gemsSurvey['gsu_id_survey'] = $this->_surveyId; $this->exists = true; return 1; } } else { return 0; } }
/** * Update the track, both in the database and in memory. * * @param array $values The values that this token should be set to * @param int $userId The current user * @return int 1 if data changed, 0 otherwise */ private function _update(array $values, $userId) { if ($this->tracker->filterChangesOnly($this->_trackData, $values)) { if (\Gems_Tracker::$verbose) { $echo = ''; foreach ($values as $key => $val) { $echo .= $key . ': ' . $this->_trackData[$key] . ' => ' . $val . "\n"; } \MUtil_Echo::r($echo, 'Updated values for ' . $this->_trackId); } if (!isset($values['gto_changed'])) { $values['gtr_changed'] = new \MUtil_Db_Expr_CurrentTimestamp(); } if (!isset($values['gtr_changed_by'])) { $values['gtr_changed_by'] = $userId; } // Update values in this object $this->_trackData = $values + $this->_trackData; // return 1; return $this->db->update('gems__tracks', $values, array('gtr_id_track = ?' => $this->_trackId)); } else { return 0; } }
/** * Assign the tokens to the correct relation * * Only surveys that have not yet been answered will be assigned to the correct relation. * * @return int Number of changes tokens */ public function assignTokensToRelations() { // Find out if we have relation fields and return when none exists in this track $relationFields = $this->getTrackEngine()->getFieldsOfType('relation'); if (empty($relationFields)) { return 0; } // Check if we have a respondent relation id (grr_id) in the track fields // and assign the token to the correct relation or leave open when no // relation is defined. $this->_ensureRounds(); $relationFields = $this->getFieldData(); $fieldPrefix = \Gems\Tracker\Model\FieldMaintenanceModel::FIELDS_NAME . \Gems\Tracker\Engine\FieldsDefinition::FIELD_KEY_SEPARATOR; $changes = 0; foreach ($this->getTokens() as $token) { /* @var $token Gems_Tracker_Token */ if (!$token->isCompleted() && $token->getReceptionCode()->isSuccess()) { $roundId = $token->getRoundId(); if (!array_key_exists($roundId, $this->_rounds)) { // If not a current round for this track, do check the round when it still exists $round = $this->getTrackEngine()->getRoundModel(true, 'index')->loadFirst(array('gro_id_round' => $roundId)); } else { $round = $this->_rounds[$roundId]; } $relationFieldId = null; $relationId = null; // Read from the round if (!empty($round) && $round['gro_id_track'] == $this->getTrackId() && $round['gro_active'] == 1) { if ($round['gro_id_relationfield'] > 0) { $relationFieldId = $round['gro_id_relationfield']; } } else { // Try to read from token, as this is a token without a round $relationFieldId = $token->getRelationFieldId(); } if ($relationFieldId > 0) { $fieldKey = $fieldPrefix . $relationFieldId; if (isset($relationFields[$fieldKey])) { $relationId = (int) $relationFields[$fieldKey]; } else { $relationId = -1 * $relationFieldId; } } $changes = $changes + $token->assignTo($relationId, $relationFieldId); } } if (MUtil_Model::$verbose && $changes > 0) { MUtil_Echo::r(sprintf('%s tokens changed due to changes in respondent relation assignments.', $changes)); } return $changes; }
public function echoRules() { \MUtil_Echo::r($this->_rules); }
/** * Add prefixed paths to the registry of paths * * @param string $prefix * @param mixed $paths String or an array of strings * @param boolean $prepend Put path at the beginning of the stack (has no effect when prefix / dir already set) * @return \Gems_Loader_LoaderAbstract (continuation pattern) */ public function addPrefixPath($prefix, $path, $prepend = true) { if ($this->cascade) { $newPrefix = $prefix . '_' . $this->cascade; $newPath = $path . '/' . strtr($this->cascade, '_', '/'); } else { $newPrefix = $prefix; $newPath = $path; } if ($prepend) { $this->_dirs = array($newPrefix => $newPath) + $this->_dirs; } else { $this->_dirs[$newPrefix] = $newPath; } $this->_loader->addPrefixPath($newPrefix, $newPath, $prepend); if (\MUtil_Registry_Source::$verbose) { \MUtil_Echo::r($this->_dirs, '$this->_dirs in ' . get_class($this) . '->' . __FUNCTION__ . '():'); } return $this; }
/** * Send an email independent from the used transport * * The requisite information for the email will be found in the following * properties: * * - {@link $recipients} - list of recipients (string) * - {@link $header} - message header * - {@link $body} - message body */ protected function _sendMail() { \MUtil_Echo::r(reset($this->_headers['Subject']), reset($this->_headers['From']) . '=>' . reset($this->_headers['To'])); }
/** * Creates a new token with a new random token Id * * @param array $tokenData * @param int $userId Id of the user who takes the action (for logging) * @return string The new token Id */ public function createToken(array $tokenData, $userId) { $current = new \MUtil_Db_Expr_CurrentTimestamp(); $tokenData['gto_changed'] = $current; $tokenData['gto_changed_by'] = $userId; $tokenData['gto_created'] = $current; $tokenData['gto_created_by'] = $userId; // Wait till the last nanosecond with creating the token id $tokenData['gto_id_token'] = $this->createTokenId(); $this->db->insert('gems__tokens', $tokenData); if (\Gems_Tracker::$verbose) { \MUtil_Echo::r($tokenData, 'Created token: ' . $tokenData['gto_id_token']); } return $tokenData['gto_id_token']; }
/** * Process the changes in the model caused by dependencies, using this data. * * @param array $data The input data * @param boolean $new True when it is a new item not saved in the model * @return array The possibly change input data */ public function processDependencies(array $data, $new) { foreach ($this->_model_dependencies as $dependency) { if ($dependency instanceof DependencyInterface) { $dependsOn = $dependency->getDependsOn(); $context = array_intersect_key($data, $dependsOn); // \MUtil_Echo::track($context, $dependsOn, get_class($dependency)); // If there are required fields and all required fields are there if ($dependsOn && count($context) === count($dependsOn)) { $changes = $dependency->getChanges($context, $new); if ($changes) { if (\MUtil_Model::$verbose) { \MUtil_Echo::r($changes, 'Changes by ' . get_class($dependency)); } // Here we could allow only those changes this dependency claims to change // but as not specifying this correctly may lead to errors elsewhere // I think there is enough reason for discipline in this not to perform // this extra check. (Though I may change my mind in the future $this->_applyDependencyChanges($this, $changes, $data); } } elseif (\MUtil_Model::$verbose) { if ($dependsOn) { $missing = array_diff_key($dependsOn, $data); if (1 === count($missing)) { $msg = "Missing field %s for dependency class %s"; $fld = reset($missing); } else { $msg = "Missing fields %s for dependency class %s"; $fld = implode(', ', array_keys($missing)); } } else { $msg = "%s%s dependency is not dependent on any fields."; $fld = ''; } \MUtil_Echo::r(sprintf($msg, $fld, get_class($dependency)), 'Dependency skipped'); } } } // \MUtil_Echo::track($data); return $data; }
/** * Do a recursive find of the changes * * @param array $switches Current level of switches array * @param array $dependsOn Current level of $dependsOn array * @param array $context Context * @return array name => array(setting => value) */ protected function _findChanges(array $switches, array $dependsOn, array $context) { // Found it when depends on is empty if (!$dependsOn) { return $switches; } $name = array_shift($dependsOn); // When there is no data, return no changes if (!array_key_exists($name, $context)) { if (\MUtil_Model::$verbose) { $names = array_diff_key($this->_dependentOn, $context); \MUtil_Echo::r(implode(', ', $names), 'Name(s) not found in ' . get_class($this)); } return array(); } $value = $context[$name]; if ($value) { // All true cases foreach ($switches as $key => $rest) { if ($value == $key) { return $this->_findChanges($rest, $dependsOn, $context); } } } else { // For non-true value we use exact type comparison, except when both are zero's if (null === $value) { foreach ($switches as $key => $rest) { if (null === $key) { return $this->_findChanges($rest, $dependsOn, $context); } } } elseif (0 === $value || "0" === $value) { foreach ($switches as $key => $rest) { if (0 === $key || "0" === $key) { return $this->_findChanges($rest, $dependsOn, $context); } } } elseif ("" === $value) { foreach ($switches as $key => $rest) { if ("" === $key) { return $this->_findChanges($rest, $dependsOn, $context); } } } } if (\MUtil_Model::$verbose) { \MUtil_Echo::track($this->_switches, $this->_dependentOn, $this->_effecteds); \MUtil_Echo::r("Value '{$value}' not found for field {$name} among the values: " . implode(', ', array_keys($switches)), 'Value not found in ' . get_class($this)); } return array(); }
/** * Returns a nested array containing the items requested. * * @param array $filter Filter array, num keys contain fixed expresions, text keys are equal or one of filters * @param array $sort Sort array field name => sort type * @return array Nested array or false */ protected function _load(array $filter, array $sort) { $setcount = 0; $results = array(); if (isset($filter[$this->textFilterField])) { $textFilter = $filter[$this->textFilterField]; unset($filter[$this->textFilterField]); } else { $textFilter = false; } foreach ($this->_getFilterModels($filter) as $name => $model) { if ($model instanceof \MUtil_Model_ModelAbstract) { $modelFilter = $this->_map($filter, $name, false, true); if (isset($this->_unionMapsTo[$name]) && $this->_unionMapsTo[$name]) { // Translate the texts filters foreach ($modelFilter as $key => $value) { if (is_numeric($key) && is_string($value)) { $modelFilter[$key] = strtr($value, $this->_unionMapsTo[$name]); } } } if (\MUtil_Model::$verbose) { \MUtil_Echo::r($modelFilter, "Filter for model {$name}."); } if ($textFilter) { // Text filter is always on visible fields and uses multiOptions if (isset($this->_unionMapsTo[$name]) && $this->_unionMapsTo[$name]) { foreach ($this->getCol('label') as $fname => $label) { if (isset($this->_unionMapsTo[$name][$fname])) { $mname = $this->_unionMapsTo[$name][$fname]; } else { $mname = $fname; } $model->set($mname, 'label', $label, 'multiOptions', $this->get($fname, 'multiOptions')); } } else { foreach ($this->getCol('label') as $fname => $label) { $model->set($fname, 'label', $label, 'multiOptions', $this->get($fname, 'multiOptions')); } } $modelFilter = array_merge($modelFilter, $model->getTextSearchFilter($textFilter)); } $resultset = $model->load($modelFilter, $this->_map($sort, $name, false, false)); if ($resultset) { $sub = array($this->_modelField => $name); foreach ($resultset as $row) { $results[] = $sub + $this->_map($row, $name, true, false); } $setcount = $setcount + 1; } } } if ($setcount && $sort) { $results = $this->_sortData($results, $sort); } return $results; }
/** * Process the data and return the answers that should be changed. * * Storing the changed values is handled by the calling function. * * @param \Gems_Tracker_Token $token Gems token object * @return array Containing the changed values */ public function processTokenData(\Gems_Tracker_Token $token) { $result = var_export($token->getRawAnswers(), true); \MUtil_Echo::r($result, $token->getTokenId()); return false; }
/** * Apply this source to the target. * * @param \MUtil_Registry_TargetInterface $target * @return boolean True if $target is OK with loaded requests */ public function applySource(\MUtil_Registry_TargetInterface $target) { foreach ($target->getRegistryRequests() as $name) { if (!$this->_applySourceContainers($target, $name)) { if (self::$verbose) { \MUtil_Echo::r('Missed resource: ' . get_class($target) . '->' . $name); } /* else { echo '<br/>missed ' . $name . "\n"; } // */ } } $result = $target->checkRegistryRequestsAnswers(); $target->afterRegistry(); return $result; }