/**
  * 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;
                 }
             }
         }
     }
 }
Beispiel #3
0
 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);
     }
 }