Merge pull request #430 from bolt/stopwatch-trait-for-widgets

Stopwatch trait for widgets
This commit is contained in:
Bob den Otter
2019-05-27 19:40:38 +02:00
committed by GitHub
11 changed files with 104 additions and 68 deletions

View File

@@ -55,6 +55,6 @@ trait CacheTrait
private function createKey()
{
return $this->getName() . $this->getTarget() . $this->getZone() . $this->getPriority();
return sprintf('%s-%s-%s', $this->getSlug(), $this->getZone(), $this->getCacheDuration());
}
}

View File

@@ -4,9 +4,11 @@ declare(strict_types=1);
namespace Bolt\Widget\Injector;
use Bolt\Widget\CacheAware;
use Bolt\Widget\RequestAware;
use Bolt\Widget\ResponseAware;
use Bolt\Widget\WidgetInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Tightenco\Collect\Support\Collection;
@@ -44,7 +46,7 @@ class QueueProcessor
return $response;
}
public function process(Response $response, Request $request, Collection $queue, string $zone): void
public function process(Response $response, Request $request, Collection $queue, CacheInterface $cache, string $zone): void
{
/** @var WidgetInterface $widget */
foreach ($queue as $widget) {
@@ -55,6 +57,9 @@ class QueueProcessor
if ($widget instanceof ResponseAware) {
$widget->setResponse($response);
}
if ($widget instanceof CacheAware) {
$widget->setCache($cache);
}
$this->injector->inject($widget, $response);
}
}

View File

@@ -12,9 +12,10 @@ use Bolt\Widget\Injector\RequestZone;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class NewsWidget extends BaseWidget implements TwigAware, RequestAware, CacheAware
class NewsWidget extends BaseWidget implements TwigAware, RequestAware, CacheAware, StopwatchAware
{
use CacheTrait;
use StopwatchTrait;
protected $name = 'News Widget';
protected $target = AdditionalTarget::WIDGET_BACK_DASHBOARD_ASIDE_TOP;

View File

@@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\Request;
trait RequestTrait
{
/** @var Request */
private $request;
public function setRequest(Request $request): self

View File

@@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\Response;
trait ResponseTrait
{
/** @var Response */
private $response;
public function setResponse(Response $response): self

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Bolt\Widget;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* Interface StopwatchAware - Widgets that implement this interface, will have
* their execution time show up in Symfony's Profiler
*/
interface StopwatchAware extends WidgetInterface
{
public function startStopwatch(Stopwatch $stopwatch);
public function stopStopwatch();
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Bolt\Widget;
use Symfony\Component\Stopwatch\Stopwatch;
trait StopwatchTrait
{
/** @var Stopwatch */
private $stopwatch;
public function startStopwatch(Stopwatch $stopwatch): void
{
$this->stopwatch = $stopwatch;
$this->stopwatch->start('widget.' . $this->getSlug());
}
public function stopStopwatch(): void
{
$this->stopwatch->stop('widget.' . $this->getSlug());
}
}

View File

@@ -9,6 +9,7 @@ use Twig\Environment;
trait TwigTrait
{
/** @var Environment */
private $twig;
public function setTwig(Environment $twig): self

View File

@@ -9,13 +9,17 @@ use Bolt\Widget\Injector\RequestZone;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class WeatherWidget extends BaseWidget implements TwigAware
class WeatherWidget extends BaseWidget implements TwigAware, CacheAware, StopwatchAware
{
use CacheTrait;
use StopwatchTrait;
protected $name = 'Weather Widget';
protected $target = AdditionalTarget::WIDGET_BACK_DASHBOARD_ASIDE_TOP;
protected $priority = 200;
protected $template = '@bolt/widgets/weather.twig';
protected $zone = RequestZone::BACKEND;
protected $cacheDuration = 3600;
/** @var string Open API key, don't use more than once per second */
public const KEY = '0acbdeea56dfafe244ac87707c5fdcb2';

View File

@@ -8,12 +8,14 @@ use Bolt\Widget\CacheAware;
use Bolt\Widget\Injector\QueueProcessor;
use Bolt\Widget\Injector\RequestZone;
use Bolt\Widget\RequestAware;
use Bolt\Widget\StopwatchAware;
use Bolt\Widget\TwigAware;
use Bolt\Widget\WidgetInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Stopwatch\Stopwatch;
use Tightenco\Collect\Support\Collection;
use Twig\Environment;
@@ -37,13 +39,22 @@ class Widgets
/** @var CacheInterface */
private $cache;
public function __construct(RequestStack $requestStack, QueueProcessor $queueProcessor, Environment $twig, CacheInterface $cache)
{
/** @var Stopwatch */
private $stopwatch;
public function __construct(
RequestStack $requestStack,
QueueProcessor $queueProcessor,
Environment $twig,
CacheInterface $cache,
Stopwatch $stopwatch
) {
$this->queue = new Collection([]);
$this->requestStack = $requestStack;
$this->queueProcessor = $queueProcessor;
$this->twig = $twig;
$this->cache = $cache;
$this->stopwatch = $stopwatch;
}
public function registerWidget(WidgetInterface $widget): void
@@ -85,6 +96,10 @@ class Widgets
private function invokeWidget(WidgetInterface $widget, array $params = []): string
{
if ($widget instanceof StopwatchAware) {
$widget->startStopwatch($this->stopwatch);
}
if ($widget instanceof RequestAware) {
$widget->setRequest($this->requestStack->getCurrentRequest());
}
@@ -94,7 +109,13 @@ class Widgets
}
// Call the magic `__invoke` method on the $widget object
return $widget($params);
$renderedWidget = $widget($params);
if ($widget instanceof StopwatchAware) {
$widget->stopStopwatch();
}
return $renderedWidget;
}
public function processQueue(Response $response): Response
@@ -111,11 +132,12 @@ class Widgets
}
$queue = $this->queue;
$cache = $this->cache;
return $this->queueProcessor->guardResponse(
$response,
function (Response $response) use ($request, $queue, $zone): void {
$this->queueProcessor->process($response, $request, $queue, $zone);
function (Response $response) use ($request, $queue, $cache, $zone): void {
$this->queueProcessor->process($response, $request, $queue, $cache, $zone);
}
);
}

View File

@@ -19,26 +19,34 @@ use Symfony\Component\Cache\Simple\Psr6Cache;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Stopwatch\Stopwatch;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class WidgetsTest extends StringTestCase
{
public function testProcessWidgetsInQueue(): void
private function getWidgetsObject(array $templates = ['weather.twig' => '[Hello, weather!]'], $zone = RequestZone::BACKEND): Widgets
{
$queueProcessor = new QueueProcessor(new HtmlInjector());
$requestStack = new RequestStack();
$request = Request::createFromGlobals();
RequestZone::setToRequest($request, RequestZone::BACKEND);
RequestZone::setToRequest($request, $zone);
$requestStack->push($request);
$loader = new ArrayLoader(['weather.twig' => '[Hello, weather!]']);
$loader = new ArrayLoader($templates);
$twig = new Environment($loader);
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$stopwatch = new Stopwatch();
return new Widgets($requestStack, $queueProcessor, $twig, $cache, $stopwatch);
}
public function testProcessWidgetsInQueue(): void
{
$widgets = $this->getWidgetsObject();
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$response = new Response('<html><body>foo</body></html>');
$snippet = (new SnippetWidget())
@@ -54,16 +62,7 @@ class WidgetsTest extends StringTestCase
public function testRenderWidget(): void
{
$queueProcessor = new QueueProcessor(new HtmlInjector());
$requestStack = new RequestStack();
$requestStack->push(Request::createFromGlobals());
$loader = new ArrayLoader(['weather.twig' => '[Hello, weather!]']);
$twig = new Environment($loader);
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$widgets = $this->getWidgetsObject();
$weatherWidget = new WeatherWidget();
$weatherWidget->setTemplate('weather.twig');
@@ -79,16 +78,7 @@ class WidgetsTest extends StringTestCase
public function testRenderWidgetWithExtraParameters(): void
{
$queueProcessor = new QueueProcessor(new HtmlInjector());
$requestStack = new RequestStack();
$requestStack->push(Request::createFromGlobals());
$loader = new ArrayLoader(['dummy.twig' => '[Hello, {{ foo }}!]']);
$twig = new Environment($loader);
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$widgets = $this->getWidgetsObject(['dummy.twig' => '[Hello, {{ foo }}!]']);
$widget = new DummyWidget();
$widget->setTemplate('dummy.twig');
@@ -103,17 +93,7 @@ class WidgetsTest extends StringTestCase
public function testProcessHeaderWidget(): void
{
$request = new Request();
RequestZone::setToRequest($request, RequestZone::FRONTEND);
$requestStack = new RequestStack();
$requestStack->push($request);
$queueProcessor = new QueueProcessor(new HtmlInjector());
$twig = new Environment(new ArrayLoader());
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$widgets = $this->getWidgetsObject([], RequestZone::FRONTEND);
$response = new Response('<html><body>foo</body></html>');
@@ -127,18 +107,7 @@ class WidgetsTest extends StringTestCase
public function testProcessWeatherWidgetInTarget(): void
{
$request = new Request();
RequestZone::setToRequest($request, RequestZone::BACKEND);
$requestStack = new RequestStack();
$requestStack->push($request);
$queueProcessor = new QueueProcessor(new HtmlInjector());
$loader = new ArrayLoader(['weather.twig' => '[Hello, weather!]']);
$twig = new Environment($loader);
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$widgets = $this->getWidgetsObject();
$response = new Response('<html><body>foo</body></html>');
@@ -159,18 +128,7 @@ class WidgetsTest extends StringTestCase
public function testProcessWeatherWidgetInTarget2(): void
{
$request = new Request();
RequestZone::setToRequest($request, RequestZone::BACKEND);
$requestStack = new RequestStack();
$requestStack->push($request);
$queueProcessor = new QueueProcessor(new HtmlInjector());
$loader = new ArrayLoader(['weather.twig' => '[Hello, weather!]']);
$twig = new Environment($loader);
$cache = new Psr6Cache(new TraceableAdapter(new FilesystemAdapter()));
$widgets = new Widgets($requestStack, $queueProcessor, $twig, $cache);
$widgets = $this->getWidgetsObject();
$response = new Response('<html><body>foo</body></html>');