Skip to content

Commit

Permalink
Merge pull request #4067 from pamil/channel-cached-contexts
Browse files Browse the repository at this point in the history
[Channel] Cached per request channel context
  • Loading branch information
Paweł Jędrzejewski committed Feb 10, 2016
2 parents 77d4177 + 599d6d7 commit 33f9ae0
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/Sylius/Bundle/ChannelBundle/Resources/config/services.xml
Expand Up @@ -23,22 +23,22 @@
</parameters>

<services>
<service id="sylius.context.channel.composite" class="%sylius.context.channel.composite.class%" />
<service id="sylius.context.channel.composite" class="%sylius.context.channel.composite.class%" public="false" />

<service id="sylius.context.channel.request_based" class="%sylius.context.channel.request_based.class%">
<service id="sylius.context.channel.request_based" class="%sylius.context.channel.request_based.class%" public="false">
<argument type="service" id="sylius.context.channel.request_based.resolver" />
<argument type="service" id="request_stack" />
<tag name="sylius.context.channel" />
</service>

<service id="sylius.context.channel.single_channel" class="%sylius.context.channel.single_channel.class%">
<service id="sylius.context.channel.single_channel" class="%sylius.context.channel.single_channel.class%" public="false">
<argument type="service" id="sylius.repository.channel" />
<tag name="sylius.context.channel" priority="-128"/>
</service>

<service id="sylius.context.channel.request_based.resolver.composite" class="%sylius.context.channel.request_based.resolver.composite.class%" />
<service id="sylius.context.channel.request_based.resolver.composite" class="%sylius.context.channel.request_based.resolver.composite.class%" public="false"/>

<service id="sylius.context.channel.request_based.resolver.hostname_based" class="%sylius.context.channel.request_based.resolver.hostname_based.class%">
<service id="sylius.context.channel.request_based.resolver.hostname_based" class="%sylius.context.channel.request_based.resolver.hostname_based.class%" public="false">
<argument type="service" id="sylius.repository.channel" />
<tag name="sylius.context.channel.request_based.resolver" />
</service>
Expand Down
6 changes: 6 additions & 0 deletions src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
Expand Up @@ -22,6 +22,7 @@
<parameter key="sylius.settings_schema.security.class">Sylius\Bundle\CoreBundle\Settings\SecuritySettingsSchema</parameter>

<parameter key="sylius.context.currency.class">Sylius\Bundle\CoreBundle\Context\CurrencyContext</parameter>
<parameter key="sylius.context.channel.cached.class">Sylius\Component\Channel\Context\CachedPerRequestChannelContext</parameter>

<parameter key="sylius.checkout_scenario.class">Sylius\Bundle\CoreBundle\Checkout\CheckoutProcessScenario</parameter>
<parameter key="sylius.checkout_step.security.class">Sylius\Bundle\CoreBundle\Checkout\Step\SecurityStep</parameter>
Expand Down Expand Up @@ -128,6 +129,11 @@
<tag name="sylius.settings_schema" namespace="sylius_security" />
</service>

<service id="sylius.context.channel.cached" class="%sylius.context.channel.cached.class%" decorates="sylius.context.channel" public="false">
<argument type="service" id="sylius.context.channel.cached.inner" />
<argument type="service" id="request_stack" />
</service>

<!-- cart -->
<service id="sylius.cart_item_resolver.default" class="%sylius.cart_item_resolver.default.class%">
<argument type="service" id="sylius.cart_provider" />
Expand Down
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sylius\Component\Channel\Context;

use Sylius\Component\Channel\Model\ChannelInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
final class CachedPerRequestChannelContext implements ChannelContextInterface
{
/**
* @var ChannelContextInterface
*/
private $decoratedChannelContext;

/**
* @var RequestStack
*/
private $requestStack;

/**
* @var \SplObjectStorage|ChannelInterface[]
*/
private $requestToChannelMap;

/**
* @param ChannelContextInterface $decoratedChannelContext
* @param RequestStack $requestStack
*/
public function __construct(ChannelContextInterface $decoratedChannelContext, RequestStack $requestStack)
{
$this->decoratedChannelContext = $decoratedChannelContext;
$this->requestStack = $requestStack;

$this->requestToChannelMap = new \SplObjectStorage();
}

/**
* {@inheritdoc}
*/
public function getChannel()
{
$objectIdentifier = $this->requestStack->getMasterRequest();

if (null === $objectIdentifier) {
return $this->decoratedChannelContext->getChannel();
}

if (!isset($this->requestToChannelMap[$objectIdentifier])) {
$this->requestToChannelMap[$objectIdentifier] = $this->decoratedChannelContext->getChannel();
}

return $this->requestToChannelMap[$objectIdentifier];
}
}
@@ -0,0 +1,103 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace spec\Sylius\Component\Channel\Context;

use PhpSpec\ObjectBehavior;
use Sylius\Component\Channel\Context\CachedPerRequestChannelContext;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* @mixin CachedPerRequestChannelContext
*
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
class CachedPerRequestChannelContextSpec extends ObjectBehavior
{
function let(ChannelContextInterface $decoratedChannelContext, RequestStack $requestStack)
{
$this->beConstructedWith($decoratedChannelContext, $requestStack);
}

function it_is_initializable()
{
$this->shouldHaveType('Sylius\Component\Channel\Context\CachedPerRequestChannelContext');
}

function it_implements_channel_context_interface()
{
$this->shouldImplement(ChannelContextInterface::class);
}

function it_caches_channels_for_the_same_request(
ChannelContextInterface $decoratedChannelContext,
RequestStack $requestStack,
Request $request,
ChannelInterface $channel
) {
$requestStack->getMasterRequest()->willReturn($request, $request);

$decoratedChannelContext->getChannel()->willReturn($channel)->shouldBeCalledTimes(1);

$this->getChannel()->shouldReturn($channel);
$this->getChannel()->shouldReturn($channel);
}

function it_does_not_cache_channels_for_different_requests(
ChannelContextInterface $decoratedChannelContext,
RequestStack $requestStack,
Request $firstRequest,
Request $secondRequest,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
) {
$requestStack->getMasterRequest()->willReturn($firstRequest, $secondRequest);

$decoratedChannelContext->getChannel()->willReturn($firstChannel, $secondChannel);

$this->getChannel()->shouldReturn($firstChannel);
$this->getChannel()->shouldReturn($secondChannel);
}

function it_caches_channels_for_the_same_request_even_if_there_are_other_request_in_between(
ChannelContextInterface $decoratedChannelContext,
RequestStack $requestStack,
Request $firstRequest,
Request $secondRequest,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
) {
$requestStack->getMasterRequest()->willReturn($firstRequest, $secondRequest, $firstRequest);

$decoratedChannelContext->getChannel()->willReturn($firstChannel, $secondChannel)->shouldBeCalledTimes(2);

$this->getChannel()->shouldReturn($firstChannel);
$this->getChannel()->shouldReturn($secondChannel);
$this->getChannel()->shouldReturn($firstChannel);
}

function it_does_not_cache_results_while_there_are_no_master_requests(
ChannelContextInterface $decoratedChannelContext,
RequestStack $requestStack,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
) {
$requestStack->getMasterRequest()->willReturn(null, null);

$decoratedChannelContext->getChannel()->willReturn($firstChannel, $secondChannel)->shouldBeCalledTimes(2);

$this->getChannel()->shouldReturn($firstChannel);
$this->getChannel()->shouldReturn($secondChannel);
}
}

0 comments on commit 33f9ae0

Please sign in to comment.