在Sylius的单一渠道上的多个主题的想法

时间:2016-05-17 05:01:40

标签: symfony themes sylius

对于我的项目,我需要针对不同设备的多个主题设计,但现在在一个频道中,只能选择一个主题。

例如, 如果我有频道"日本"在日本销售,我想为每个设备多个主题:移动,平板电脑和PC。因此,用户将看到主题取决于他们的设备。

我需要一些关于使用单一渠道为不同设备创建多个主题/风格的想法。

那么,有什么想法吗?

1 个答案:

答案 0 :(得分:2)

好的,负责当前主题的服务是sylius.context.theme服务。如果您使用Sylius完整堆栈,则将使用ChannelBasedThemeContext(请参阅:https://github.com/Sylius/SyliusCoreBundle/blob/master/Theme/ChannelBasedThemeContext.php)。正如您在其源代码中看到的,它只是在当前通道上找到您通过主题themeName属性安装的主题。了解这一点,我们可以通过实施ThemeContextInterface来实现自己的。因为在您的情况下,您可能希望在主题japan_mobile不存在时回退到默认行为,我们将装饰sylius.context.theme服务,而不是替换它!

让我们首先创建Acme\AppBundle\Theme\DeviceBasedThemeContext

namespace Acme\AppBundle\Theme\DeviceBasedThemeContext;

use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Channel\Context\ChannelNotFoundException;
use Sylius\Component\Core\Model\ChannelInterface;

final class DeviceBasedThemeContext implements ThemeContextInterface
{
    /**
     * @var ThemeContextInterface
     */
    private $decoratedThemeContext;

    /**
     * @var ChannelContextInterface
     */
    private $channelContext;

    /**
     * @var ThemeRepositoryInterface
     */
    private $themeRepository;

    /**
     * @param ThemeContextInterface $decoratedThemeContext
     * @param ChannelContextInterface $channelContext
     * @param ThemeRepositoryInterface $themeRepository
     */
    public function __construct(
        ThemeContextInterface decoratedThemeContext,
        ChannelContextInterface $channelContext, 
        ThemeRepositoryInterface $themeRepository
    ) {
        $this->decoratedThemeContext = $decoratedThemeContext;
        $this->channelContext = $channelContext;
        $this->themeRepository = $themeRepository;
    }

    /**
     * {@inheritdoc}
     */
    public function getTheme()
    {
        try {
            /** @var ChannelInterface $channel */
            $channel = $this->channelContext->getChannel();

            $deviceThemeName = $channel->getThemeName().’_’.$this->getDeviceName();

            // try to find a device specific version of this theme, if so, it will use that one
            if ($theme = $this->themeRepository->findOneByName($deviceThemeName) {
                return $theme;
            }

            // fallback to use the default theme resolving logic
            return $this->decoratedThemeContext->getTheme();
        } catch (ChannelNotFoundException $exception) {
            return null;
        } catch (\Exception $exception) {
            return null;
        }
    }

    private function getDeviceName()
    {
        // here you should return the proper device name
        return ‘mobile’;
    }
}

现在我们已完成主题上下文,我们必须让服务容器识别它,我们通过装饰现有的sylius.theme.context服务(a.k.a。ChannelBasedThemeContext)来做到这一点。

因此,在services.xml添加以下服务:

<service id="acme.context.theme.device_based" class="Acme\AppBundle\Theme\DeviceBasedThemeContext"
         decorates=“sylius.theme.context”>
    <argument type=“service” id=“acme.context.theme.device_based.inner”/>
    <argument type=“service” id=“sylius.context.channel”/>
    <argument type=“service” id=“sylius.repository.theme”/>
</service>

完成!如果您清除了缓存,现在应首先尝试加载japan_mobile,如果它不存在则只会加载japan主题(假设当前频道有japan作为其主题名称)。

我希望这是一个足够明确的指令来帮助您前进,因为注入可以检测到正确设备名称的服务并不是很难做到,但是如果您无法弄清楚,请告诉我,我将通过实施这一点来扩展它。