/** * @param Context $context * @param bool $ignore_failures * * @return mixed */ public function resolve($context, $ignore_failures = False) { if ($this->var instanceof Variable) { try { $obj = $this->var->resolve($context); } catch (VariableDoesNotExist $e) { if ($ignore_failures) { $obj = null; } else { if (Dja::getSetting('TEMPLATE_STRING_IF_INVALID')) { if (DjaBase::$invalid_var_format_string === null) { DjaBase::$invalid_var_format_string = strpos(Dja::getSetting('TEMPLATE_STRING_IF_INVALID'), '%s') !== False; } if (DjaBase::$invalid_var_format_string) { return sprintf(Dja::getSetting('TEMPLATE_STRING_IF_INVALID'), $this->var); } return Dja::getSetting('TEMPLATE_STRING_IF_INVALID'); } else { $obj = Dja::getSetting('TEMPLATE_STRING_IF_INVALID'); } } } } else { $obj = $this->var; } foreach ($this->filters as $filter) { list($func, $args, $n_) = $filter; $arg_vals = array(); foreach ($args as $arg_data) { /** @var $arg Variable|string */ list($lookup, $arg) = $arg_data; if (!$lookup) { $arg_vals[] = mark_safe($arg); } else { $arg_vals[] = $arg->resolve($context); } } if (py_getattr($func, 'expects_localtime', False)) { $obj = localtime($obj, $context->use_tz); } $func_ = $func->closure; if (py_getattr($func, 'needs_autoescape', False)) { $new_obj = call_user_func_array($func_, array_merge(array($obj, $context->autoescape), $arg_vals)); } else { $new_obj = call_user_func_array($func_, array_merge(array($obj), $arg_vals)); } if (py_getattr($func, 'is_safe', False) && $obj instanceof SafeData) { $obj = mark_safe($new_obj); } else { if ($obj instanceof EscapeData) { $obj = mark_for_escaping($new_obj); } else { $obj = $new_obj; } } } return $obj; }
* @var Parser $parser * @var Token $token */ $bits = $token->splitContents(); if (count($bits) < 2) { throw new TemplateSyntaxError('\'include\' tag takes at least one argument: the name of the template to be included.'); } $options = array(); $remaining_bits = py_slice($bits, 2); while ($remaining_bits) { $option = py_arr_pop($remaining_bits, 0); if (isset($options[$option])) { throw new TemplateSyntaxError('The ' . $option . ' option was specified more than once.'); } if ($option == 'with') { $value = DjaBase::tokenKwargs($remaining_bits, $parser, False); if (!$value) { throw new TemplateSyntaxError('"with" in \'include\' tag needs at least one keyword argument.'); } } elseif ($option == 'only') { $value = True; } else { throw new TemplateSyntaxError('Unknown argument for \'include\' tag: ' . $option . '.'); } $options[$option] = $value; } $isolated_context = py_arr_get($options, 'only', False); $namemap = py_arr_get($options, 'with', array()); $path = $bits[1]; if (in_array($path[0], array('"', "'")) && py_arr_get($path, -1) == $path[0]) { return new ConstantIncludeNode(py_slice($path, 1, -1), $namemap, $isolated_context);
/** * Return a list of tokens from a given template_string * * @return array */ public function tokenize() { $result = array(); $upto = 0; $matches = new PyReFinditer(DjaBase::getReTag(), $this->template_string); /** @var $match pyReMatchObject */ foreach ($matches as $match) { list($start, $end) = $match->span(); if ($start > $upto) { $result[] = $this->createToken(py_slice($this->template_string, $upto, $start), False, array($upto, $start)); $upto = $start; } $result[] = $this->createToken(py_slice($this->template_string, $start, $end), True, array($start, $end)); $upto = $end; } $last_bit = py_slice($this->template_string, $upto); if ($last_bit) { $result[] = $this->createToken($last_bit, False, array($upto, $upto + strlen($last_bit))); } return $result; }
<?php define('DJA_VERSION', '0.1'); define('DJA_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR); set_include_path(get_include_path() . PATH_SEPARATOR . DJA_ROOT . PATH_SEPARATOR . DJA_ROOT . 'loaders' . PATH_SEPARATOR . DJA_ROOT . 'template'); require 'dja_pyhelpers.php'; require 'dja_utils.php'; require 'template/base.php'; require 'template/context.php'; require 'template/loader.php'; require 'template/smartif.php'; require 'template/debug.php'; DjaBase::addToBuiltins('defaulttags'); DjaBase::addToBuiltins('defaultfilters'); class Dja { /** * Dja default settings. * * @var array */ private static $_settings_default = array('LANGUAGE_CODE' => 'en-us', 'USE_L10N' => False, 'USE_I18N' => True, 'MEDIA_URL' => '', 'STATIC_ROOT' => '', 'STATIC_URL' => null, 'USE_TZ' => False, 'DATE_FORMAT' => 'N j, Y', 'DATETIME_FORMAT' => 'N j, Y, P', 'SHORT_DATE_FORMAT' => 'm/d/Y', 'SHORT_DATETIME_FORMAT' => 'm/d/Y P', 'TEMPLATE_CACHE' => False, 'TEMPLATE_DEBUG' => False, 'TEMPLATE_STRING_IF_INVALID' => '', 'TEMPLATE_LOADERS' => array('loaders.filesystem.FilesystemLoader'), 'TEMPLATE_DIRS' => array(), 'ALLOWED_INCLUDE_ROOTS' => array(), 'INSTALLED_APPS' => array()); /** * @var null|array */ private static $_settings = null; /** * @var null|IDjaUrlDispatcher */ private static $_url_dispatcher = null; /**
$lib->tag('widthratio', function ($parser, $token) { /** * @var Parser $parser * @var Token $token */ $bits = py_str_split($token->contents); if (count($bits) != 4) { throw new TemplateSyntaxError('widthratio takes three arguments'); } list($tag, $this_value_expr, $max_value_expr, $max_width) = $bits; return new WidthRatioNode($parser->compileFilter($this_value_expr), $parser->compileFilter($max_value_expr), $parser->compileFilter($max_width)); }); $lib->tag('with', function ($parser, $token) { /** * @var Parser $parser * @var Token $token */ $bits = py_str_split($token->contents); $remaining_bits = py_slice($bits, 1); $extra_context = DjaBase::tokenKwargs($remaining_bits, $parser, True); if (!$extra_context) { throw new TemplateSyntaxError('\'with\' expected at least one variable assignment'); } if ($remaining_bits) { throw new TemplateSyntaxError('\'with\' received an invalid token: ' . $remaining_bits[0]); } $nodelist = $parser->parse(array('endwith')); $parser->deleteFirstToken(); return new WithNode(null, null, $nodelist, $extra_context); }); return $lib;
public function testTemplates() { $template_tests = self::getTemplateTests(); $filter_tests = get_filter_tests(); /* * Quickly check that we aren't accidentally using a name in both * template and filter tests. */ $overlapping_names = array(); $tkeys_ = array_keys($template_tests); foreach ($filter_tests as $name => $v) { if (array_key_exists($name, $tkeys_)) { $overlapping_names[] = $name; } } if (!empty($overlapping_names)) { throw new Exception('Duplicate test name(s): ' . join(', ', $overlapping_names)); } $template_tests = array_merge($template_tests, $filter_tests); $tpls_ = array(); foreach ($template_tests as $name => $t) { $tpls_[$name] = $t[0]; } $cache_loader = setup_test_template_loader($tpls_, True); $failures = array(); $tests = $template_tests; ksort($tests); // Turn TEMPLATE_DEBUG off, because tests assume that. $old_debug = Dja::getSetting('TEMPLATE_DEBUG'); Dja::setSetting('TEMPLATE_DEBUG', True); // Set TEMPLATE_STRING_IF_INVALID to a known string. $old_invalid = Dja::getSetting('TEMPLATE_STRING_IF_INVALID'); $expected_invalid_str = 'INVALID'; // Set ALLOWED_INCLUDE_ROOTS so that ssi works. $old_allowed_include_roots = Dja::getSetting('ALLOWED_INCLUDE_ROOTS'); Dja::setSetting('ALLOWED_INCLUDE_ROOTS', array(realpath(dirname(__FILE__)))); // Warm the URL reversing cache. This ensures we don't pay the cost // warming the cache during one of the tests. Dja::getUrlDispatcher()->reverse('regressiontests.templates.views.client_action', null, array(), array('id' => 0, 'action' => "update")); foreach ($tests as $name => $vals) { if (is_array($vals[2])) { $normal_string_result = $vals[2][0]; $invalid_string_result = $vals[2][1]; if (is_array($invalid_string_result)) { $expected_invalid_str = 'INVALID %s'; $invalid_string_result = sprintf($invalid_string_result[0], $invalid_string_result[1]); DjaBase::$invalid_var_format_string = True; } if (isset($vals[2][2])) { $template_debug_result = $vals[2][2]; } else { $template_debug_result = $normal_string_result; } } else { $normal_string_result = $vals[2]; $invalid_string_result = $vals[2]; $template_debug_result = $vals[2]; } if (isset($vals[1]['LANGUAGE_CODE'])) { Dja::getI18n()->activate($vals[1]['LANGUAGE_CODE']); } else { Dja::getI18n()->activate('en-us'); } foreach (array(array('', False, $normal_string_result), array($expected_invalid_str, False, $invalid_string_result), array('', True, $template_debug_result)) as $itm) { list($invalid_str, $template_debug, $result) = $itm; Dja::setSetting('TEMPLATE_STRING_IF_INVALID', $invalid_str); Dja::setSetting('TEMPLATE_DEBUG', $template_debug); foreach (array(False, True) as $is_cached) { $fail_str_ = 'Template test (Cached=' . ($is_cached ? 'TRUE' : 'FALSE') . ', TEMPLATE_STRING_IF_INVALID=\'' . $invalid_str . '\', TEMPLATE_DEBUG=' . ($template_debug ? 'TRUE' : 'FALSE') . '): ' . $name . ' -- FAILED. '; try { try { $test_template = DjaLoader::getTemplate($name); } catch (ShouldNotExecuteException $e) { $failures[] = $fail_str_ . 'Template loading invoked method that shouldn\'t have been invoked.'; } try { $output = self::render($test_template, $vals); } catch (ShouldNotExecuteException $e) { $failures[] = $fail_str_ . 'Template loading invoked method that shouldn\'t have been invoked.'; } } catch (ContextStackException $e) { $failures[] = $fail_str_ . 'Context stack was left imbalanced'; continue; } catch (Exception $e) { $exc_type = get_class($e); $exc_value = $e->getMessage(); $exc_tb = $e->getTraceAsString(); if ($exc_type != $result) { $tb = $exc_tb; $failures[] = $fail_str_ . 'Got ' . $exc_type . ', exception: ' . $exc_value . "\n" . $tb; } continue; } if ($output != $result) { $failures[] = $fail_str_ . 'Expected [' . $result . '], got [' . $output . ']'; } } $cache_loader->reset(); } if (isset($vals[1]['LANGUAGE_CODE'])) { Dja::getI18n()->deactivate(); } if (DjaBase::$invalid_var_format_string) { $expected_invalid_str = 'INVALID'; DjaBase::$invalid_var_format_string = False; } } restore_template_loaders(); Dja::getI18n()->deactivate(); Dja::setSetting('TEMPLATE_STRING_IF_INVALID', $old_invalid); Dja::setSetting('TEMPLATE_DEBUG', $old_debug); Dja::setSetting('ALLOWED_INCLUDE_ROOTS', $old_allowed_include_roots); $sep_ = str_pad('', 70, '-'); $this->assertEquals(array(), $failures, "Tests failed:\n{$sep_}\n" . join("\n{$sep_}\n", $failures)); }
*/ public function loadTemplateSource($template_name, $template_dirs = null) { throw new NotImplementedError(); } /** * Resets any state maintained by the loader instance (e.g., cached * templates or cached loader modules). */ public function reset() { } } class LoaderOrigin extends Origin { public function __construct($display_name, $loader, $name, $dirs) { parent::__construct($display_name); $this->loader = $loader; $this->loadname = $name; $this->dirs = $dirs; } public function reload() { $loader = $this->loader; $res_ = $loader($this->loadname, $this->dirs); return $res_[0]; } } DjaBase::addToBuiltins('loader_tags');