/** * @param $template_name * @param null|array $template_dirs * @return array */ public function loadTemplate($template_name, $template_dirs = null) { $key = $template_name; if ($template_dirs) { // If template directories were specified, use a hash to differentiate $key = join('-', array($template_name, sha1(join('|', $template_dirs)))); } if (!isset($this->template_cache[$key])) { list($template, $origin) = $this->findTemplate($template_name, $template_dirs); if (!py_hasattr($template, 'render')) { try { $template = DjaLoader::getTemplateFromString($template, $origin, $template_name); } catch (TemplateDoesNotExist $e) { /* * If compiling the template we found raises TemplateDoesNotExist, * back off to returning the source and display name for the template * we were asked to load. This allows for correct identification (later) * of the actual template that does not exist. */ return array($template, $origin); } } $this->template_cache[$key] = $template; } return array($this->template_cache[$key], null); }
/** * @param Context $context * * @return Template * @throws TemplateSyntaxError */ public function getParent($context) { if ($this->parent_name_expr) { $parent = $this->parent_name_expr->resolve($context); } else { $parent = $this->parent_name; } if (!$parent) { $error_msg = 'Invalid template name in \'extends\' tag: ' . $parent . '.'; if ($this->parent_name_expr) { $error_msg .= ' Got this from the \'' . $this->parent_name_expr->token . '\' variable.'; } throw new TemplateSyntaxError($error_msg); } if (py_hasattr($parent, 'render')) { return $parent; // parent is a Template object } return DjaLoader::getTemplate($parent); }
/** * @param Context $context * @return SafeString|string * @throws Exception|TypeError|VariableDoesNotExist * @throws RuntimeError */ public function render($context) { if (isset($context['forloop'])) { $parentloop = $context['forloop']; } else { $parentloop = array(); } $context->push(); try { $values = $this->sequence->resolve($context, True); } catch (VariableDoesNotExist $e) { $values = array(); } if ($values === null) { $values = array(); } elseif (is_string($values)) { // We convert a string to array to make it iterable. $values = str_split($values); // TODO Check unicode handling. } if (!is_array($values) && !$values instanceof Iterator) { throw new RuntimeError('Noniterable "' . $values . '" is passed to for loop.'); } $len_values = count($values); if ($len_values < 1) { $context->pop(); return $this->nodelist_empty->render($context); } $nodelist = new NodeList(); if ($this->is_reversed) { $values_ = $values; krsort($values_); $values = $values_; unset($values_); } $unpack = count($this->loopvars) > 1; // Create a forloop value in the context. We'll update counters on each iteration just below. $loop_dict = $context['forloop'] = array('parentloop' => $parentloop); foreach ($values as $i => $item) { // Shortcuts for current loop iteration number. $loop_dict['counter0'] = $i; $loop_dict['counter'] = $i + 1; // Reverse counter iteration numbers. $loop_dict['revcounter'] = $len_values - $i; $loop_dict['revcounter0'] = $len_values - $i - 1; // Boolean values designating first and last times through loop. $loop_dict['first'] = $i == 0; $loop_dict['last'] = $i == $len_values - 1; $context['forloop'] = array_merge($context['forloop'], $loop_dict); $pop_context = False; if ($unpack) { // If there are multiple loop variables, unpack the item into them. $success_ = True; try { $unpacked_vars = py_zip($this->loopvars, $item); } catch (TypeError $e) { $success_ = False; } if ($success_) { $pop_context = True; $context->update($unpacked_vars); } } else { $context[$this->loopvars[0]] = $item; } // In TEMPLATE_DEBUG mode provide source of the node which actually raised the exception if (Dja::getSetting('TEMPLATE_DEBUG')) { foreach ($this->nodelist_loop as $node) { /** @var $node Node */ try { $nodelist[] = $node->render($context); } catch (Exception $e) { if (!py_hasattr($e, 'django_template_source')) { $e->django_template_source = $node->source; } throw $e; } } } else { foreach ($this->nodelist_loop as $node) { $nodelist[] = $node->render($context); } } if ($pop_context) { /* * The loop variables were pushed on to the context so pop them * off again. This is necessary because the tag lets the length * of loopvars differ to the length of each set of items and we * don't want to leave any vars from the previous loop on the * context. */ $context->pop(); } } $context->pop(); return $nodelist->render($context); }
/** * Returns a compiled Template object for the given template name, * handling template inheritance recursively. * * @param $template_name * * @return Template */ public static function getTemplate($template_name) { $self = get_called_class(); $get_template = function () use($template_name, $self) { list($template, $origin) = $self::findTemplate($template_name); if (!py_hasattr($template, 'render')) { // template needs to be compiled $template = $self::getTemplateFromString($template, $origin, $template_name); } return $template; }; $use_cache = Dja::getSetting('TEMPLATE_CACHE'); if (!$use_cache) { return $get_template(); } $cacher = Dja::getCacheManager(); if (!($template = $cacher->get($template_name))) { $template = $get_template(); $cacher->set($template_name, $template); } return $template; }