/** * Compile handlebars template into PHP code. * * @param string $template handlebars template string * @param array<string,array|string|integer> $options LightnCandy compile time and run time options, default is array('flags' => LightnCandy::FLAG_BESTPERFORMANCE) * * @return string|false Compiled PHP code when successed. If error happened and compile failed, return false. */ public static function compile($template, $options = array('flags' => self::FLAG_BESTPERFORMANCE)) { $context = Context::create($options); if (static::handleError($context)) { return false; } $code = Compiler::compileTemplate($context, SafeString::escapeTemplate($template)); static::$lastParsed = Compiler::$lastParsed; // return false when fatal error if (static::handleError($context)) { return false; } // Or, return full PHP render codes as string return Compiler::composePHPRender($context, $code); }
/** * Read partial file content as string and store in context * * @param array<string,array|string|integer> $context Current context of compiler progress. * @param string $name partial name * * @return string|null $code compiled PHP code when success */ public static function read(&$context, $name) { $context['usedFeature']['partial']++; if (isset($context['usedPartial'][$name])) { return; } $cnt = static::resolve($context, $name); if ($cnt !== null) { $context['usedPartial'][$name] = SafeString::escapeTemplate($cnt); return static::compileDynamic($context, $name); } if (!$context['flags']['skippartial']) { $context['error'][] = "Can not find partial for '{$name}', you should provide partials or partialresolver in options"; } }
/** * Verify template * * @param array<string,array|string|integer> $context Current context * @param string $template handlebars template */ public static function verify(&$context, $template) { $template = SafeString::stripExtendedComments($template); $context['level'] = 0; Parser::setDelimiter($context); while (preg_match($context['tokens']['search'], $template, $matches)) { // Skip a token when it is slash escaped if ($context['flags']['slash'] && $matches[Token::POS_LSPACE] === '' && preg_match('/^(.*?)(\\\\+)$/s', $matches[Token::POS_LOTHER], $escmatch)) { if (strlen($escmatch[2]) % 4) { static::pushToken($context, substr($matches[Token::POS_LOTHER], 0, -2) . $context['tokens']['startchar']); $matches[Token::POS_BEGINTAG] = substr($matches[Token::POS_BEGINTAG], 1); $template = implode('', array_slice($matches, Token::POS_BEGINTAG)); continue; } else { $matches[Token::POS_LOTHER] = $escmatch[1] . str_repeat('\\', strlen($escmatch[2]) / 2); } } $context['tokens']['count']++; $V = static::token($matches, $context); static::pushLeft($context); if ($V) { if (is_array($V)) { array_push($V, $matches, $context['tokens']['partialind']); } static::pushToken($context, $V); } $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; } static::pushToken($context, $template); if ($context['level'] > 0) { array_pop($context['stack']); array_pop($context['stack']); $token = array_pop($context['stack']); $context['error'][] = 'Unclosed token ' . ($context['rawblock'] ? "{{{{{$token}}}}}" : ($context['partialblock'] ? "{{#>{$token}}}" : "{{#{$token}}}")) . ' !!'; } }