Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added TemplateFactory #2

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"symfony/yaml": "^6.0"
},
"require-dev": {
"illuminate/support": "^10.21",
"laravel/pint": "^1.2",
"pestphp/pest": "^2.6",
"pestphp/pest-plugin-arch": "^2.0",
Expand All @@ -46,7 +45,8 @@
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint",
"lint": "vendor/bin/phpstan analyse"
"lint": "vendor/bin/phpstan analyse",
"benchmark": "@php performance/benchmark.php"
},
"config": {
"sort-packages": true,
Expand Down
6 changes: 3 additions & 3 deletions performance/BenchmarkRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

class BenchmarkRunner
{
public function run(int $seconds, \Closure $callback)
public function run(int $seconds, \Closure $callback): BenchmarkResult
{
$durationNs = $seconds * 1e9;
$start = hrtime(true);

gc_collect_cycles();

$runs = [];
do {
gc_collect_cycles();

$runs[] = $this->measure($callback);
$end = hrtime(true);
} while (($end - $start) < $durationNs);
Expand Down
14 changes: 6 additions & 8 deletions performance/CompiledThemeTestTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

namespace Keepsuit\Liquid\Performance;

use Keepsuit\Liquid\Performance\Shopify\CustomFilters;
use Keepsuit\Liquid\Render\Context;
use Keepsuit\Liquid\Template;
use Keepsuit\Liquid\TemplateFactory;

class CompiledThemeTestTemplate
{
public function __construct(
protected TemplateFactory $factory,
public string $templateName,
public Template $template,
public ?Template $layout,
Expand All @@ -22,23 +23,20 @@ public function pageTemplate(): string

public function render(array $assigns = []): void
{
$content = $this->template->render($this->buildContext($assigns));

if ($this->layout) {
$this->layout->render($this->buildContext([
...$assigns,
'content_for_layout' => $this->template->render($this->buildContext($assigns)),
'content_for_layout' => $content,
]));
} else {
$this->template->render($this->buildContext($assigns));
}
}

protected function buildContext(array $assigns = []): Context
{
return new Context(
return $this->factory->newRenderContext(
staticEnvironment: $assigns,
filters: [
CustomFilters::class,
],
);
}
}
5 changes: 3 additions & 2 deletions performance/Shopify/CommentFormTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function parse(Tokenizer $tokenizer): static
public function render(Context $context): string
{
$article = $context->get($this->variableName);
assert(is_array($article));

$context->stack(function (Context $context) {
$context->set('form', [
Expand All @@ -52,10 +53,10 @@ public function render(Context $context): string
return $this->wrapInForm($article, parent::render($context));
}

protected function wrapInForm(mixed $article, string $input): string
protected function wrapInForm(array $article, string $input): string
{
return <<<HTML
<form id="article-{$article->id}-comment-form" class="comment-form" method="post" action="">
<form id="article-{$article['id']}-comment-form" class="comment-form" method="post" action="">
$input
</form>
HTML;
Expand Down
9 changes: 2 additions & 7 deletions performance/Shopify/CustomFilters.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@
namespace Keepsuit\Liquid\Performance\Shopify;

use Keepsuit\Liquid\Exceptions\InvalidArgumentException;
use Keepsuit\Liquid\Render\Context;
use Keepsuit\Liquid\Filters\FiltersProvider;

class CustomFilters
class CustomFilters extends FiltersProvider
{
public function __construct(
protected Context $context
) {
}

public function json(mixed $value): string
{
if (is_array($value) && array_key_exists('collections', $value)) {
Expand Down
2 changes: 1 addition & 1 deletion performance/Shopify/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Database

protected static ?array $tables = null;

public static function tables()
public static function tables(): array
{
if (static::$tables !== null) {
return static::$tables;
Expand Down
22 changes: 13 additions & 9 deletions performance/Shopify/PaginateTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Keepsuit\Liquid\Exceptions\InvalidArgumentException;
use Keepsuit\Liquid\Exceptions\SyntaxException;
use Keepsuit\Liquid\Nodes\Range;
use Keepsuit\Liquid\Parse\Regex;
use Keepsuit\Liquid\Parse\Tokenizer;
use Keepsuit\Liquid\Render\Context;
Expand Down Expand Up @@ -50,8 +51,11 @@ public function render(Context $context): string
$currentPage = $context->get('current_page');

$collection = $context->get($this->collectionName);
$collection = is_iterable($collection) ? iterator_to_array($collection) : $collection;

$collection = match (true) {
$collection instanceof Range => $collection->toArray(),
$collection instanceof \Iterator => iterator_to_array($collection),
default => $collection,
};
if (! is_array($collection)) {
throw new InvalidArgumentException(sprintf('Cannot paginate array %s. Not found.', $this->collectionName));
}
Expand All @@ -71,14 +75,14 @@ public function render(Context $context): string
];

if ($pageCount > 2) {
foreach (range(1, $pageCount - 1) as $page) {
foreach (range(1, (int) $pageCount - 1) as $page) {
$pagination['parts'][] = match (true) {
$currentPage === $page => $this->noLink($page),
$page === 1 => $this->link($page, $page),
$page === $pageCount - 1 => $this->link($page, $page),
$page <= $currentPage - $this->attributes['window_size'] => $this->link('...', $page),
$page >= $currentPage + $this->attributes['window_size'] => $this->link('...', $page),
default => $this->link($page, $page),
$currentPage === $page => $this->noLink((string) $page),
$page === 1 => $this->link((string) $page, $page),
$page === $pageCount - 1 => $this->link((string) $page, $page),
$page <= ($currentPage - (int) $this->attributes['window_size']) => $this->link('...', $page),
$page >= ($currentPage + (int) $this->attributes['window_size']) => $this->link('...', $page),
default => $this->link((string) $page, $page),
};
}
}
Expand Down
18 changes: 10 additions & 8 deletions performance/ThemeRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Keepsuit\Liquid\Performance\Shopify\Database;
use Keepsuit\Liquid\Support\Arr;
use Keepsuit\Liquid\Template;
use Keepsuit\Liquid\TemplateFactory;

class ThemeRunner
{
Expand All @@ -18,9 +18,10 @@ class ThemeRunner
*/
protected array $compiledTemplates;

public function __construct()
{
$files = glob(__DIR__.'/tests/**/*.liquid');
public function __construct(
protected TemplateFactory $templateFactory
) {
$files = glob(__DIR__.'/tests/**/*.liquid') ?: [];

$this->tests = Arr::compact(Arr::map($files, function (string $path) {
if (basename($path) === 'theme.liquid') {
Expand All @@ -30,9 +31,10 @@ public function __construct()
$themePath = dirname($path).'/theme.liquid';

return new ThemeTestTemplate(
factory: $this->templateFactory,
templateName: $path,
liquid: file_get_contents($path),
layoutLiquid: file_exists($themePath) ? file_get_contents($themePath) : null,
liquid: file_get_contents($path) ?: '',
layoutLiquid: file_exists($themePath) ? (file_get_contents($themePath) ?: '') : null,
);
}));

Expand All @@ -42,9 +44,9 @@ public function __construct()
public function compile(): void
{
foreach ($this->tests as $test) {
Template::parse($test->liquid);
$this->templateFactory->parse($test->liquid);
if ($test->layoutLiquid !== null) {
Template::parse($test->layoutLiquid);
$this->templateFactory->parse($test->layoutLiquid);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions performance/ThemeTestTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

namespace Keepsuit\Liquid\Performance;

use Keepsuit\Liquid\Template;
use Keepsuit\Liquid\TemplateFactory;

class ThemeTestTemplate
{
public function __construct(
protected TemplateFactory $factory,
public string $templateName,
public string $liquid,
public ?string $layoutLiquid,
Expand All @@ -20,10 +21,11 @@ public function pageTemplate(): string

public function compile(): CompiledThemeTestTemplate
{
$template = Template::parse($this->liquid);
$layout = $this->layoutLiquid !== null ? Template::parse($this->layoutLiquid) : null;
$template = $this->factory->parse($this->liquid);
$layout = $this->layoutLiquid !== null ? $this->factory->parse($this->layoutLiquid) : null;

return new CompiledThemeTestTemplate(
factory: $this->factory,
templateName: $this->templateName,
template: $template,
layout: $layout,
Expand Down
25 changes: 17 additions & 8 deletions performance/benchmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
use Keepsuit\Liquid\Performance\BenchmarkResult;
use Keepsuit\Liquid\Performance\BenchmarkRunner;
use Keepsuit\Liquid\Performance\Shopify\CommentFormTag;
use Keepsuit\Liquid\Performance\Shopify\CustomFilters;
use Keepsuit\Liquid\Performance\Shopify\PaginateTag;
use Keepsuit\Liquid\Performance\ThemeRunner;
use Keepsuit\Liquid\Template;
use Keepsuit\Liquid\TemplateFactory;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -15,28 +16,33 @@

require __DIR__.'/../vendor/autoload.php';

Template::registerTag(CommentFormTag::class);
Template::registerTag(PaginateTag::class);
$templateFactory = TemplateFactory::new()
->registerTag(CommentFormTag::class)
->registerTag(PaginateTag::class)
->registerFilter(CustomFilters::class);

(new SingleCommandApplication())
->setName('Benchmark')
->setCode(function (InputInterface $input, OutputInterface $output) {
->setCode(function (InputInterface $input, OutputInterface $output) use ($templateFactory) {
$style = new SymfonyStyle($input, $output);

$times = 10;
$warmup = 5;
$warmup = 0;

$output->writeln(sprintf('Running benchmark for %s seconds (with %s seconds warmup).', $times, $warmup));
if ($warmup > 0) {
$output->writeln(sprintf('Running benchmark for %s seconds (with %s seconds warmup).', $times, $warmup));
} else {
$output->writeln(sprintf('Running benchmark for %s seconds.', $times));
}

$benchmark = new BenchmarkRunner();
$profiler = new ThemeRunner();
$profiler = new ThemeRunner($templateFactory);

if ($warmup > 0) {
$output->writeln('Warming up...');
$benchmark->run($warmup, fn () => $profiler->compile());
}

$output->writeln('Benchmarking...');
$computeTable = $style->createTable();
$computeTable->setHeaders([
'test',
Expand All @@ -45,8 +51,11 @@
'runs',
'duration',
]);
$output->writeln('Running parse benchmark...');
outputBenchmarkResult($computeTable, 'parse', $benchmark->run($times, fn () => $profiler->compile()));
$output->writeln('Running render benchmark...');
outputBenchmarkResult($computeTable, 'render', $benchmark->run($times, fn () => $profiler->render()));
$output->writeln('Running parse & render benchmark...');
outputBenchmarkResult($computeTable, 'parse & render', $benchmark->run($times, fn () => $profiler->run()));
$computeTable->render();
})
Expand Down
15 changes: 15 additions & 0 deletions src/Concerns/ContextAware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Keepsuit\Liquid\Concerns;

use Keepsuit\Liquid\Render\Context;

trait ContextAware
{
protected Context $context;

public function setContext(Context $context): void
{
$this->context = $context;
}
}
11 changes: 3 additions & 8 deletions src/Drop.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,22 @@

namespace Keepsuit\Liquid;

use Keepsuit\Liquid\Concerns\ContextAware;
use Keepsuit\Liquid\Contracts\IsContextAware;
use Keepsuit\Liquid\Contracts\MapsToLiquid;
use Keepsuit\Liquid\Drops\DropMethodPrivate;
use Keepsuit\Liquid\Exceptions\UndefinedDropMethodException;
use Keepsuit\Liquid\Render\Context;
use Keepsuit\Liquid\Support\Str;

class Drop implements IsContextAware, MapsToLiquid
{
protected ?Context $context = null;
use ContextAware;

/**
* @var string[]
*/
private ?array $invokableMethods = null;

public function setContext(Context $context): void
{
$this->context = $context;
}

public function toLiquid(): mixed
{
return $this;
Expand All @@ -35,7 +30,7 @@ public function toLiquidValue(): mixed

protected function liquidMethodMissing(string $name): mixed
{
if ($this->context?->strictVariables) {
if ($this->context->strictVariables) {
throw new UndefinedDropMethodException($name);
}

Expand Down
11 changes: 11 additions & 0 deletions src/Filters/FiltersProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Keepsuit\Liquid\Filters;

use Keepsuit\Liquid\Concerns\ContextAware;
use Keepsuit\Liquid\Contracts\IsContextAware;

abstract class FiltersProvider implements IsContextAware
{
use ContextAware;
}
8 changes: 1 addition & 7 deletions src/Filters/StandardFilters.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,11 @@
use Keepsuit\Liquid\Contracts\MapsToLiquid;
use Keepsuit\Liquid\Drop;
use Keepsuit\Liquid\Exceptions\InvalidArgumentException;
use Keepsuit\Liquid\Render\Context;
use Keepsuit\Liquid\Support\Arr;
use Keepsuit\Liquid\Support\Str;

class StandardFilters
class StandardFilters extends FiltersProvider
{
public function __construct(
protected Context $context
) {
}

/**
* Returns the absolute value of a number.
*/
Expand Down
Loading