/** * Executes this task. */ public function main() { if ($this->path === null) { throw new BuildException('The path attribute must be specified'); } $check = new AgaviModuleFilesystemCheck(); $check->setConfigDirectory($this->project->getProperty('module.config.directory')); $check->setPath($this->path->getAbsolutePath()); if (!$check->check()) { throw new BuildException('The path attribute must be a valid module base directory'); } /* We don't know whether the module is configured or not here, so load the * values we want properly. */ $this->tryLoadAgavi(); $this->tryBootstrapAgavi(); require_once AgaviConfigCache::checkConfig(sprintf('%s/%s/module.xml', $this->path->getAbsolutePath(), (string) $this->project->getProperty('module.config.directory'))); $actionPath = AgaviToolkit::expandVariables(AgaviToolkit::expandDirectives(AgaviConfig::get(sprintf('modules.%s.agavi.action.path', strtolower($this->path->getName())), '%core.module_dir%/${moduleName}/actions/${actionName}Action.class.php')), array('moduleName' => $this->path->getName())); $pattern = '#^' . AgaviToolkit::expandVariables(str_replace('\\$\\{actionName\\}', '${actionName}', preg_quote($actionPath, '#')), array('actionName' => '(?P<action_name>.*?)')) . '$#'; $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->path->getAbsolutePath())); for (; $iterator->valid(); $iterator->next()) { $rdi = $iterator->getInnerIterator(); if ($rdi->isDot() || !$rdi->isFile()) { continue; } $file = $rdi->getPathname(); if (preg_match($pattern, $file, $matches)) { $this->log(str_replace(DIRECTORY_SEPARATOR, '.', $matches['action_name'])); } } }
private function loadModuleFiles($tm, &$files) { $default = $tm->getDefaultDomain(); $translator = $tm->getDomainTranslator($default, AgaviTranslationManager::MESSAGE); $locale = $tm->getCurrentLocale(); $domains = array(); if ($translator instanceof AppKitGettextTranslator) { $basePath = $translator->getDomainPathPattern(); $modules = scandir(AgaviToolkit::literalize("%core.module_dir%")); foreach ($modules as $m) { if ($m != '.' && $m != '..') { $domains[] = $m; } } foreach ($domains as $domain) { $path = AgaviToolkit::expandVariables($basePath, array('domain' => $domain)); foreach (AgaviLocale::getLookupPath($tm->getCurrentLocale()->getIdentifier()) as $prefix) { $result = $this->loadFile($path, $prefix, $files); if ($result) { $files[$domain] = $result; } } } } }
public function testExpandVariables() { $string = "{bbq}"; $arguments = array('hehe' => 'hihi', '{bbq}' => 'soon'); $this->assertEquals('{bbq}', AgaviToolkit::expandVariables($string)); $this->assertEquals('${foo}', AgaviToolkit::expandVariables('$foo')); $this->assertEquals('${foo}', AgaviToolkit::expandVariables('{$foo}')); }
/** * Get the full, resolved stream location name to the template resource. * * @return string A PHP stream resource identifier. * * @throws AgaviException If the template could not be found. * * @author David Zülke <*****@*****.**> * @since 0.11.0 */ public function getResourceStreamIdentifier() { $template = $this->getParameter('template'); if ($template === null) { // no template set, we return null so nothing gets rendered return null; } $args = array(); if (AgaviConfig::get('core.use_translation')) { // i18n is enabled, build a list of sprintf args with the locale identifier foreach (AgaviLocale::getLookupPath($this->context->getTranslationManager()->getCurrentLocaleIdentifier()) as $identifier) { $args[] = array('locale' => $identifier); } } if (empty($args)) { $args[] = array(); // add one empty arg to always trigger target lookups (even if i18n is disabled etc.) } $scheme = $this->getParameter('scheme'); // FIXME: a simple workaround for broken ubuntu and debian packages (fixed already), we can remove that for final 0.11 if ($scheme != 'file' && !in_array($scheme, stream_get_wrappers())) { throw new AgaviException('Unknown stream wrapper "' . $scheme . '", must be one of "' . implode('", "', stream_get_wrappers()) . '".'); } $check = $this->getParameter('check'); $attempts = array(); // try each of the patterns foreach ((array) $this->getParameter('targets', array()) as $pattern) { // try pattern with each argument list foreach ($args as $arg) { $target = AgaviToolkit::expandVariables($pattern, array_merge(array_filter($this->getParameters(), 'is_scalar'), array_filter($this->getParameters(), 'is_null'), $arg)); // FIXME (should they fix it): don't add file:// because suhosin's include whitelist is empty by default, does not contain 'file' as allowed uri scheme if ($scheme != 'file') { $target = $scheme . '://' . $target; } if (!$check || is_readable($target)) { return $target; } $attempts[] = $target; } } // no template found, time to throw an exception throw new AgaviException('Template "' . $template . '" could not be found. Paths tried:' . "\n" . implode("\n", $attempts)); }
/** * Loads the data from the data file for the given domain with the current * locale. * * @param string The domain to load the data for. * * @author Dominik del Bondio <*****@*****.**> * @since 0.11.0 */ public function loadDomainData($domain) { $localeName = $this->locale->getIdentifier(); $localeNameBases = AgaviLocale::getLookupPath($localeName); if (!isset($this->domainPaths[$domain])) { if (!$this->domainPathPattern) { throw new AgaviException('Using domain "' . $domain . '" which has no path specified'); } else { $basePath = $this->domainPathPattern; } } else { $basePath = $this->domainPaths[$domain]; } $basePath = AgaviToolkit::expandVariables($basePath, array('domain' => $domain)); $data = array(); foreach ($localeNameBases as $localeNameBase) { $fileName = AgaviToolkit::expandVariables($basePath, array('locale' => $localeNameBase)); if ($fileName === $basePath) { // no replacing of $locale happened $fileName = $basePath . '/' . $localeNameBase . '.mo'; } if (is_readable($fileName)) { $fileData = AgaviGettextMoReader::readFile($fileName); // instead of array_merge, which doesn't handle null bytes in keys properly. careful, the order matters here. $data = $fileData + $data; } } $headers = array(); if (count($data)) { $headerData = str_replace("\r", '', $data['']); $headerLines = explode("\n", $headerData); foreach ($headerLines as $line) { $values = explode(':', $line, 2); // skip empty / invalid lines if (count($values) == 2) { $headers[$values[0]] = $values[1]; } } } $this->pluralFormFunc = null; if (isset($headers['Plural-Forms'])) { $pf = $headers['Plural-Forms']; if (preg_match('#nplurals=\\d+;\\s+plural=(.*)$#D', $pf, $match)) { $funcCode = $match[1]; $validOpChars = array(' ', 'n', '!', '&', '|', '<', '>', '(', ')', '?', ':', ';', '=', '+', '*', '/', '%', '-'); if (preg_match('#[^\\d' . preg_quote(implode('', $validOpChars), '#') . ']#', $funcCode, $errorMatch)) { throw new AgaviException('Illegal character ' . $errorMatch[0] . ' in plural form ' . $funcCode); } // add parenthesis around all ternary expressions. This is done // to make the ternary operator (?) have precedence over the delimiter (:) // This will transform // "a ? 1 : b ? c ? 3 : 4 : 2" to "(a ? 1 : (b ? (c ? 3 : 4) : 2))" and // "a ? b ? c ? d ? 5 : 4 : 3 : 2 : 1" to "(a ? (b ? (c ? (d ? 5 : 4) : 3) : 2) : 1)" // "a ? b ? c ? 4 : 3 : d ? 5 : 2 : 1" to "(a ? (b ? (c ? 4 : 3) : (d ? 5 : 2)) : 1)" // "a ? b ? c ? 4 : 3 : d ? 5 : e ? 6 : 2 : 1" to "(a ? (b ? (c ? 4 : 3) : (d ? 5 : (e ? 6 : 2))) : 1)" $funcCode = rtrim($funcCode, ';'); $parts = preg_split('#(\\?|\\:)#', $funcCode, -1, PREG_SPLIT_DELIM_CAPTURE); $parenthesisCount = 0; $unclosedParenthesisCount = 0; $firstParenthesis = true; $funcCode = ''; for ($i = 0, $c = count($parts); $i < $c; ++$i) { $lastPart = $i > 0 ? $parts[$i - 1] : null; $part = $parts[$i]; $nextPart = $i + 1 < $c ? $parts[$i + 1] : null; if ($nextPart == '?') { if ($lastPart == ':') { // keep track of parenthesis which need to be closed // directly after this ternary expression ++$unclosedParenthesisCount; --$parenthesisCount; } $funcCode .= ' (' . $part; ++$parenthesisCount; } elseif ($lastPart == ':') { $funcCode .= $part . ') '; if ($unclosedParenthesisCount > 0) { $funcCode .= str_repeat(')', $unclosedParenthesisCount); $unclosedParenthesisCount = 0; } --$parenthesisCount; } else { $funcCode .= $part; } } if ($parenthesisCount > 0) { // add the missing top level parenthesis $funcCode .= str_repeat(')', $parenthesisCount); } $funcCode .= ';'; $funcCode = 'return ' . str_replace('n', '$n', $funcCode); $this->pluralFormFunc = create_function('$n', $funcCode); } } $this->domainData[$domain] = array('headers' => $headers, 'msgs' => $data); }
/** * Insert the error messages from the given incidents into the given element * using the given rules. * * @param DOMElement The element to work on. * @param array An array of insertion rules * @param array An array of AgaviValidationIncidents. * * @return bool Whether or not the inserts were successful. * * @author David Zülke <*****@*****.**> * @since 0.11.0 */ protected function insertErrorMessages(DOMElement $element, array $rules, array $incidents) { $errorMessages = array(); foreach ($incidents as $incident) { if ($incident->getSeverity() <= AgaviValidator::SILENT) { continue; } foreach ($incident->getErrors() as $error) { if (($errorMessage = $error->getMessage()) !== null && $errorMessage !== '') { $errorMessages[] = $errorMessage; } } } if (!$errorMessages) { // nothing to do here return true; } $luie = libxml_use_internal_errors(true); libxml_clear_errors(); $insertSuccessful = false; foreach ($rules as $xpathExpression => $errorMessageInfo) { $targets = $this->xpath->query(AgaviToolkit::expandVariables($xpathExpression, array('htmlnsPrefix' => $this->xmlnsPrefix)), $element); if (!$targets || !$targets->length) { continue; } if (!is_array($errorMessageInfo)) { $errorMessageInfo = array('markup' => $errorMessageInfo); } if (isset($errorMessageInfo['markup'])) { $errorMarkup = $errorMessageInfo['markup']; } else { throw new AgaviException('Form Population Filter was unable to insert an error message into the document using the XPath expression "' . $xpathExpression . '" because the element information did not contain markup to use.'); } if (isset($errorMessageInfo['location'])) { $errorLocation = $errorMessageInfo['location']; } else { $errorLocation = 'after'; } if (isset($errorMessageInfo['container'])) { $errorContainer = $errorMessageInfo['container']; } else { $errorContainer = null; } $errorElements = array(); foreach ($errorMessages as $errorMessage) { if (is_string($errorMarkup)) { // it's a string with the HTML to insert // %s is the placeholder in the HTML for the error message $errorElement = $this->doc->createDocumentFragment(); $errorElement->appendXML(AgaviToolkit::expandVariables($errorMarkup, array('elementId' => htmlspecialchars($element->getAttribute('id'), ENT_QUOTES, 'UTF-8'), 'elementName' => htmlspecialchars($element->getAttribute('name'), ENT_QUOTES, 'UTF-8'), 'errorMessage' => htmlspecialchars($errorMessage, ENT_QUOTES, 'UTF-8')))); } elseif (is_callable($errorMarkup)) { // it's a callback we can use to get a DOMElement // we give it the element as the first, and the error message as the second argument $errorElement = call_user_func($errorMarkup, $element, $errorMessage); $this->doc->importNode($errorElement, true); } else { throw new AgaviException('Form Population Filter was unable to insert an error message into the document using the XPath expression "' . $xpathExpression . '" because the element information could not be evaluated as an XML/HTML fragment or as a PHP callback.'); } $errorElements[] = $errorElement; } if ($errorContainer) { // we have an error container. // that means that instead of inserting each message element, we add the messages into the container // then, the container is the only element scheduled for insertion $errorStrings = array(); // add all error XML strings to an array foreach ($errorElements as $errorElement) { $errorStrings[] = $errorElement->ownerDocument->saveXML($errorElement); } // create the container element and replace the errors placeholder in the container if (is_string($errorContainer)) { // it's a string with the HTML to insert // %s is the placeholder in the HTML for the error message $containerElement = $this->doc->createDocumentFragment(); $containerElement->appendXML(AgaviToolkit::expandVariables($errorContainer, array('elementId' => htmlspecialchars($element->getAttribute('id'), ENT_QUOTES, 'UTF-8'), 'elementName' => htmlspecialchars($element->getAttribute('name'), ENT_QUOTES, 'UTF-8'), 'errorMessages' => implode("\n", $errorStrings)))); } elseif (is_callable($errorContainer)) { // it's a callback we can use to get a DOMElement // we give it the element as the first, and the error messages array(!) as the second argument $containerElement = call_user_func($errorContainer, $element, $errorStrings); $this->doc->importNode($containerElement, true); } else { throw new AgaviException('Form Population Filter was unable to insert an error message container into the document using the XPath expression "' . $xpathExpression . '" because the element information could not be evaluated as an XML/HTML fragment or as a PHP callback.'); } // and now the trick: set the error container element as the only one in the errorElements variable // that way, it's going to get inserted for us as if it were a normal error message element, using the location specified $errorElements = array($containerElement); } if (libxml_get_last_error() !== false) { $errors = array(); foreach (libxml_get_errors() as $error) { $errors[] = sprintf('[%s #%d] Line %d: %s', $error->level == LIBXML_ERR_WARNING ? 'Warning' : ($error->level == LIBXML_ERR_ERROR ? 'Error' : 'Fatal'), $error->code, $error->line, $error->message); } libxml_clear_errors(); libxml_use_internal_errors($luie); $emsg = sprintf('Form Population Filter was unable to insert an error message into the document using the XPath expression "%s" due to the following error%s: ' . "\n\n%s", $xpathExpression, count($errors) > 1 ? 's' : '', implode("\n", $errors)); throw new AgaviParseException($emsg); } foreach ($errorElements as $errorElement) { foreach ($targets as $target) { // in case the target yielded more than one location, we need to clone the element // because the document fragment node will be corrupted after an insert $clonedErrorElement = $errorElement->cloneNode(true); if ($errorLocation == 'before') { $target->parentNode->insertBefore($clonedErrorElement, $target); } elseif ($errorLocation == 'after') { // check if there is a following sibling, then insert before that one // if not, append to parent if ($target->nextSibling) { $target->parentNode->insertBefore($clonedErrorElement, $target->nextSibling); } else { $target->parentNode->appendChild($clonedErrorElement); } } elseif ($errorLocation == 'replace') { $target->parentNode->replaceChild($clonedErrorElement, $target); } else { $target->appendChild($clonedErrorElement); } } } // and break the foreach, our expression matched after all - no need to look further $insertSuccessful = true; break; } libxml_clear_errors(); libxml_use_internal_errors($luie); return $insertSuccessful; }
/** * Get the full, resolved stream location name to the template resource. * * @return string A PHP stream resource identifier. * * @throws AgaviException If the template could not be found. * * @author David Zülke <*****@*****.**> * @since 0.11.0 */ public function getResourceStreamIdentifier() { $retval = null; $template = $this->getParameter('template'); if ($template === null) { // no template set, we return null so nothing gets rendered return null; } elseif (AgaviToolkit::isPathAbsolute($template)) { // the template is an absolute path, ignore the dir $directory = dirname($template); $template = basename($template); } else { $directory = $this->getParameter('directory'); } // treat the directory as sprintf format string and inject module name $directory = AgaviToolkit::expandVariables($directory, array_merge(array_filter($this->getParameters(), 'is_scalar'), array_filter($this->getParameters(), 'is_null'))); $this->setParameter('directory', $directory); $this->setParameter('template', $template); if (!$this->hasParameter('extension')) { $this->setParameter('extension', $this->renderer->getDefaultExtension()); } // everything set up for the parent return parent::getResourceStreamIdentifier(); }
/** * Evaluates a given AgaviConfig per-module directive using the given info. * * @param string The name of the module * @param string The relevant name fragment of the directive * @param array The variables to expand in the directive value. * * @return string The final value * * @author David Zülke <*****@*****.**> * @since 1.0.0 */ public static function evaluateModuleDirective($moduleName, $directiveNameFragment, $variables = array()) { return AgaviToolkit::expandVariables(AgaviToolkit::expandDirectives(AgaviConfig::get(sprintf('modules.%s.%s', strtolower($moduleName), $directiveNameFragment))), $variables); }
/** * Matches the input against the routing info and sets the info as request * parameter. * * @return mixed An AgaviExecutionContainer as a result of this execution, * or an AgaviResponse if a callback returned one. * * @author Dominik del Bondio <*****@*****.**> * @since 0.11.0 */ public function execute() { $rq = $this->context->getRequest(); $rd = $rq->getRequestData(); $tm = $this->context->getTranslationManager(); $container = $this->context->getController()->createExecutionContainer(); if (!$this->isEnabled()) { // routing disabled, just bail out here return $container; } $matchedRoutes = array(); $input = $this->input; $vars = array(); $ot = null; $locale = null; $method = null; $umap = $rq->getParameter('use_module_action_parameters'); $ma = $rq->getParameter('module_accessor'); $aa = $rq->getParameter('action_accessor'); $requestMethod = $rq->getMethod(); $routes = array(); // get all top level routes foreach ($this->routes as $name => $route) { if (!$route['opt']['parent']) { $routes[] = $name; } } // prepare the working stack with the root routes $routeStack = array($routes); do { $routes = array_pop($routeStack); foreach ($routes as $key) { $route =& $this->routes[$key]; $opts =& $route['opt']; if (count($opts['constraint']) == 0 || in_array($requestMethod, $opts['constraint'])) { if (count($opts['callbacks']) > 0 && !isset($route['callback_instances'])) { foreach ($opts['callbacks'] as $key => $callback) { $instance = new $callback['class'](); $instance->initialize($this->context, $route); $instance->setParameters($callback['parameters']); $route['callback_instances'][$key] = $instance; } } $match = array(); if ($this->parseInput($route, $input, $match)) { $varsBackup = $vars; // backup the container, must be done here already if (count($opts['callbacks']) > 0) { $containerBackup = $container; $container = clone $container; } $ign = array(); if (count($opts['ignores']) > 0) { $ign = array_flip($opts['ignores']); } foreach ($opts['defaults'] as $key => $value) { if (!isset($ign[$key]) && $value->getValue()) { $vars[$key] = $value->getValue(); } } foreach ($route['par'] as $param) { if (isset($match[$param]) && $match[$param][1] != -1) { $vars[$param] = $match[$param][0]; } } foreach ($match as $name => $m) { if (is_string($name) && $m[1] != -1) { $route['matches'][$name] = $m[0]; } } // /* ! Only use the parameters from this route for expandVariables ! // matches are arrays with value and offset due to PREG_OFFSET_CAPTURE, and we want index 0, the value, which reset() will give us. Long story short, this removes the offset from the individual match $matchvals = array_map('reset', $match); // */ /* ! Use the parameters from ALL routes for expandVariables ! $matchvals = $vars; // ignores need of the current route need to be added $foreach($opts['ignores'] as $ignore) { if(isset($match[$ignore]) && $match[$ignore][1] != -1) { $matchvals[$ignore] = $match[$ignore][0]; } } // */ if ($opts['module']) { $module = AgaviToolkit::expandVariables($opts['module'], $matchvals); $container->setModuleName($module); if ($umap) { $vars[$ma] = $module; } } if ($opts['action']) { $action = AgaviToolkit::expandVariables($opts['action'], $matchvals); $container->setActionName($action); if ($umap) { $vars[$aa] = $action; } } if ($opts['output_type']) { // set the output type if necessary // here no explicit check is done, since in 0.11 this is compared against null // which can never be the result of expandVariables $ot = AgaviToolkit::expandVariables($opts['output_type'], $matchvals); // we need to wrap in try/catch here (but not further down after the callbacks have run) for BC // and because it makes sense - maybe a callback checks or changes the output type name try { $container->setOutputType($this->context->getController()->getOutputType($ot)); } catch (AgaviException $e) { } } if ($opts['locale']) { $localeBackup = $tm->getCurrentLocaleIdentifier(); // set the locale if necessary if ($locale = AgaviToolkit::expandVariables($opts['locale'], $matchvals)) { // the if is here for bc reasons, since if $opts['locale'] only contains variable parts // expandVariables could possibly return an empty string in which case the pre 1.0 routing // didn't set the variable // we need to wrap in try/catch here (but not further down after the callbacks have run) for BC // and because it makes sense - maybe a callback checks or changes the locale name try { $tm->setLocale($locale); } catch (AgaviException $e) { } } } else { // unset it explicitly, so that further down, the isset() check doesn't set back a value from a previous iteration! $localeBackup = null; } if ($opts['method']) { // set the request method if necessary if ($method = AgaviToolkit::expandVariables($opts['method'], $matchvals)) { // the if is here for bc reasons, since if $opts['method'] only contains variable parts // expandVariables could possibly return an empty string in which case the pre 1.0 routing // didn't set the variable $rq->setMethod($method); // and on the already created container, too! $container->setRequestMethod($method); } } if (count($opts['callbacks']) > 0) { if (count($opts['ignores']) > 0) { // add ignored variables to the callback vars foreach ($vars as $name => &$var) { $vars[$name] =& $var; } foreach ($opts['ignores'] as $ignore) { if (isset($match[$ignore]) && $match[$ignore][1] != -1) { $vars[$ignore] = $match[$ignore][0]; } } } $callbackSuccess = true; foreach ($route['callback_instances'] as $callbackInstance) { // call onMatched on all callbacks until one of them returns false // then restore state and call onNotMatched on that same callback // after that, call onNotMatched for all remaining callbacks of that route if ($callbackSuccess) { // backup stuff which could be changed in the callback so we are // able to determine which values were changed in the callback $oldModule = $container->getModuleName(); $oldAction = $container->getActionName(); $oldOutputTypeName = $container->getOutputType() ? $container->getOutputType()->getName() : null; if (null === $tm) { $oldLocale = null; } else { $oldLocale = $tm->getCurrentLocaleIdentifier(); } $oldRequestMethod = $rq->getMethod(); $oldContainerMethod = $container->getRequestMethod(); $onMatched = $callbackInstance->onMatched($vars, $container); if ($onMatched instanceof AgaviResponse) { return $onMatched; } if (!$onMatched) { $callbackSuccess = false; // reset the matches array. it must be populated by the time onMatched() is called so matches can be modified in a callback $route['matches'] = array(); // restore the variables from the variables which were set before this route matched $vars = $varsBackup; // reset all relevant container data we already set in the container for this (now non matching) route $container = $containerBackup; // restore locale if (isset($localeBackup)) { $tm->setLocale($localeBackup); } // restore request method $rq->setMethod($container->getRequestMethod()); } } // always call onNotMatched if $callbackSuccess == false, even if we just called onMatched() on the same instance. this is expected behavior if (!$callbackSuccess) { $onNotMatched = $callbackInstance->onNotMatched($container); if ($onNotMatched instanceof AgaviResponse) { return $onNotMatched; } // continue with the next callback continue; } // /* ! Only use the parameters from this route for expandVariables ! $expandVars = $vars; $routeParamsAsKey = array_flip($route['par']); // only use parameters which are defined in this route or are new foreach ($expandVars as $name => $value) { if (!isset($routeParamsAsKey[$name]) && array_key_exists($name, $varsBackup)) { unset($expandVars[$name]); } } // */ /* ! Use the parameters from ALL routes for expandVariables ! $expandVars = $vars; // */ // if the callback didn't change the value, execute expandVariables again since // the callback could have changed one of the values which expandVariables uses // to evaluate the contents of the attribute in question (e.g. module="${zomg}") if ($opts['module'] && $oldModule == $container->getModuleName() && (!$umap || !array_key_exists($ma, $vars) || $oldModule == $vars[$ma])) { $module = AgaviToolkit::expandVariables($opts['module'], $expandVars); $container->setModuleName($module); if ($umap) { $vars[$ma] = $module; } } if ($opts['action'] && $oldAction == $container->getActionName() && (!$umap || !array_key_exists($aa, $vars) || $oldAction == $vars[$aa])) { $action = AgaviToolkit::expandVariables($opts['action'], $expandVars); $container->setActionName($action); if ($umap) { $vars[$aa] = $action; } } if ($opts['output_type'] && $oldOutputTypeName == ($container->getOutputType() ? $container->getOutputType()->getName() : null)) { $ot = AgaviToolkit::expandVariables($opts['output_type'], $expandVars); $container->setOutputType($this->context->getController()->getOutputType($ot)); } if ($opts['locale'] && $oldLocale == $tm->getCurrentLocaleIdentifier()) { if ($locale = AgaviToolkit::expandVariables($opts['locale'], $expandVars)) { // see above for the reason of the if $tm->setLocale($locale); } } if ($opts['method']) { if ($oldRequestMethod == $rq->getMethod() && $oldContainerMethod == $container->getRequestMethod()) { if ($method = AgaviToolkit::expandVariables($opts['method'], $expandVars)) { // see above for the reason of the if $rq->setMethod($method); $container->setRequestMethod($method); } } elseif ($oldContainerMethod != $container->getRequestMethod()) { // copy the request method to the request (a method set on the container // in a callback always has precedence over request methods set on the request) $rq->setMethod($container->getRequestMethod()); } elseif ($oldRequestMethod != $rq->getMethod()) { // copy the request method to the container $container->setRequestMethod($rq->getMethod()); } } // one last thing we need to do: see if one of the callbacks modified the 'action' or 'module' vars inside $vars if $umap is on // we then need to write those back to the container, unless they changed THERE, too, in which case the container values take precedence if ($umap && $oldModule == $container->getModuleName() && array_key_exists($ma, $vars) && $vars[$ma] != $oldModule) { $container->setModuleName($vars[$ma]); } if ($umap && $oldAction == $container->getActionName() && array_key_exists($aa, $vars) && $vars[$aa] != $oldAction) { $container->setActionName($vars[$aa]); } } if (!$callbackSuccess) { // jump straight to the next route continue; } else { // We added the ignores to the route variables so the callback receives them, so restore them from vars backup. // Restoring them from the backup is necessary since otherwise a value which has been set before this route // and which was ignored in this route would take the ignored value instead of keeping the old one. // And variables which have not been set in an earlier routes need to be removed again foreach ($opts['ignores'] as $ignore) { if (array_key_exists($ignore, $varsBackup)) { $vars[$ignore] = $varsBackup[$ignore]; } else { unset($vars[$ignore]); } } } } $matchedRoutes[] = $opts['name']; if ($opts['cut'] || count($opts['childs']) && $opts['cut'] === null) { if ($route['opt']['source'] !== null) { $s =& $this->sources[$route['opt']['source']]; } else { $s =& $input; } $ni = ''; // if the route didn't match from the start of the input preserve the 'prefix' if ($match[0][1] > 0) { $ni = substr($s, 0, $match[0][1]); } $ni .= substr($s, $match[0][1] + strlen($match[0][0])); $s = $ni; } if (count($opts['childs'])) { // our childs need to be processed next and stop processing 'afterwards' $routeStack[] = $opts['childs']; break; } if ($opts['stop']) { break; } } else { if (count($opts['callbacks']) > 0) { foreach ($route['callback_instances'] as $callbackInstance) { $onNotMatched = $callbackInstance->onNotMatched($container); if ($onNotMatched instanceof AgaviResponse) { return $onNotMatched; } } } } } } } while (count($routeStack) > 0); // put the vars into the request $rd->setParameters($vars); if ($container->getModuleName() === null || $container->getActionName() === null) { // no route which supplied the required parameters matched, use 404 action $container->setModuleName(AgaviConfig::get('actions.error_404_module')); $container->setActionName(AgaviConfig::get('actions.error_404_action')); if ($umap) { $rd->setParameters(array($ma => $container->getModuleName(), $aa => $container->getActionName())); } } // set the list of matched route names as a request attribute $rq->setAttribute('matched_routes', $matchedRoutes, 'org.agavi.routing'); // return a list of matched route names return $container; }
/** * Executes the task. */ public function main() { if ($this->property === null) { throw new BuildException('The property attribute must be specified'); } if ($this->string === null) { throw new BuildException('The string attribute must be specified'); } $this->tryLoadAgavi(); $this->tryBootstrapAgavi(); $assigns = array(); foreach ($this->variables as $variable) { $assigns[$variable->getName()] = $variable->getValue(); } $result = AgaviToolkit::expandVariables($this->expandDirectives ? AgaviToolkit::expandDirectives($this->string) : $this->string, $assigns); $this->project->setUserProperty($this->property, $result); }
/** * Executes the task. */ public function main() { if ($this->name === null) { throw new BuildException('The name attribute must be specified'); } $this->tryLoadAgavi(); $this->tryBootstrapAgavi(); /* Oookay. This is interesting. */ $moduleName = $this->name; require_once AgaviConfigCache::checkConfig(sprintf('%s/%s/%s/%s/module.xml', (string) $this->project->getProperty('project.directory'), (string) $this->project->getProperty('project.directory.app.modules'), $this->name, (string) $this->project->getProperty('module.config.directory'))); /* Set up us the values. * * XXX: With regards to the defaults: * * You might expect to use the <property>.default properties defined in * build.xml. But this is not so; consider that someone might have decided * to upgrade their project properties but still have some legacy modules * lying around. We need to use the actual Agavi defaults to ensure * consistency. * * If you change this, you're f*****g asking for it. */ $values = array(); $lowerModuleName = strtolower($moduleName); $values['action.path'] = AgaviConfig::get(sprintf('modules.%s.agavi.action.path', $lowerModuleName), '%core.module_dir%/${moduleName}/actions/${actionName}Action.class.php'); $values['action.path'] = AgaviToolkit::expandVariables($values['action.path'], array('moduleName' => $moduleName)); $values['cache.path'] = AgaviConfig::get(sprintf('modules.%s.agavi.cache.path', $lowerModuleName), '%core.module_dir%/${moduleName}/cache/${actionName}.xml'); $values['cache.path'] = AgaviToolkit::expandVariables($values['cache.path'], array('moduleName' => $moduleName)); $values['templates.directory'] = AgaviConfig::get(sprintf('modules.%s.agavi.template.directory', $lowerModuleName), '%core.module_dir%/${module}/templates'); $values['templates.directory'] = AgaviToolkit::expandVariables($values['templates.directory'], array('module' => $moduleName)); $values['validate.path'] = AgaviConfig::get(sprintf('modules.%s.agavi.validate.path', $lowerModuleName), '%core.module_dir%/${moduleName}/validate/${actionName}.xml'); $values['validate.path'] = AgaviToolkit::expandVariables($values['validate.path'], array('moduleName' => $moduleName)); $values['view.path'] = AgaviConfig::get(sprintf('modules.%s.agavi.view.path', $lowerModuleName), '%core.module_dir%/${moduleName}/views/${viewName}View.class.php'); $values['view.path'] = AgaviToolkit::expandVariables($values['view.path'], array('moduleName' => $moduleName)); $values['view.name'] = AgaviConfig::get(sprintf('modules.%s.agavi.view.name', $lowerModuleName), '${actionName}${viewName}'); /* Main screen turn on. */ foreach ($values as $name => $value) { $this->project->setUserProperty(sprintf('%s.%s', $this->prefix, $name), $value); } }