Extract ThemeBundle

This commit is contained in:
Kamil Kokot 2019-02-18 18:09:07 +01:00
parent e5fb7a7e2d
commit 3b2ca7bc41
No known key found for this signature in database
GPG key ID: 7BD76F7054D93C89
219 changed files with 2 additions and 12502 deletions

View file

@ -52,8 +52,9 @@
"sonata-project/intl-bundle": "^2.2",
"stof/doctrine-extensions-bundle": "^1.2",
"swiftmailer/swiftmailer": "^6.0",
"sylius/fixtures-bundle": "~1.1.15",
"sylius-labs/association-hydrator": "^1.0",
"sylius/fixtures-bundle": "~1.1.15",
"sylius/theme-bundle": "~1.1.15",
"symfony/monolog-bundle": "^3.0",
"symfony/polyfill-iconv": "^1.3",
"symfony/polyfill-intl-icu": "^1.3",
@ -144,7 +145,6 @@
"sylius/taxation-bundle": "self.version",
"sylius/taxonomy": "self.version",
"sylius/taxonomy-bundle": "self.version",
"sylius/theme-bundle": "self.version",
"sylius/ui-bundle": "self.version",
"sylius/user": "self.version",
"sylius/user-bundle": "self.version",

View file

@ -45,7 +45,6 @@ suites:
ShopBundle: { namespace: Sylius\Bundle\ShopBundle, psr4_prefix: Sylius\Bundle\ShopBundle, spec_path: src/Sylius/Bundle/ShopBundle, src_path: src/Sylius/Bundle/ShopBundle }
TaxationBundle: { namespace: Sylius\Bundle\TaxationBundle, psr4_prefix: Sylius\Bundle\TaxationBundle, spec_path: src/Sylius/Bundle/TaxationBundle, src_path: src/Sylius/Bundle/TaxationBundle }
TaxonomyBundle: { namespace: Sylius\Bundle\TaxonomyBundle, psr4_prefix: Sylius\Bundle\TaxonomyBundle, spec_path: src/Sylius/Bundle/TaxonomyBundle, src_path: src/Sylius/Bundle/TaxonomyBundle }
ThemeBundle: { namespace: Sylius\Bundle\ThemeBundle, psr4_prefix: Sylius\Bundle\ThemeBundle , spec_path: src/Sylius/Bundle/ThemeBundle, src_path: src/Sylius/Bundle/ThemeBundle }
UiBundle: { namespace: Sylius\Bundle\UiBundle, psr4_prefix: Sylius\Bundle\UiBundle, spec_path: src/Sylius/Bundle/UiBundle, src_path: src/Sylius/Bundle/UiBundle }
UserBundle: { namespace: Sylius\Bundle\UserBundle, psr4_prefix: Sylius\Bundle\UserBundle, spec_path: src/Sylius/Bundle/UserBundle, src_path: src/Sylius/Bundle/UserBundle }

View file

@ -1,8 +0,0 @@
/vendor/
/bin/
/composer.phar
/composer.lock
/phpspec.yml
/phpunit.xml

View file

@ -1,280 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Installer;
use Sylius\Bundle\ThemeBundle\Asset\PathResolverInterface;
use Sylius\Bundle\ThemeBundle\HierarchyProvider\ThemeHierarchyProviderInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\KernelInterface;
final class AssetsInstaller implements AssetsInstallerInterface
{
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var KernelInterface
*/
private $kernel;
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @var ThemeHierarchyProviderInterface
*/
private $themeHierarchyProvider;
/**
* @var PathResolverInterface
*/
private $pathResolver;
/**
* @param Filesystem $filesystem
* @param KernelInterface $kernel
* @param ThemeRepositoryInterface $themeRepository
* @param ThemeHierarchyProviderInterface $themeHierarchyProvider
* @param PathResolverInterface $pathResolver
*/
public function __construct(
Filesystem $filesystem,
KernelInterface $kernel,
ThemeRepositoryInterface $themeRepository,
ThemeHierarchyProviderInterface $themeHierarchyProvider,
PathResolverInterface $pathResolver
) {
$this->filesystem = $filesystem;
$this->kernel = $kernel;
$this->themeRepository = $themeRepository;
$this->themeHierarchyProvider = $themeHierarchyProvider;
$this->pathResolver = $pathResolver;
}
/**
* {@inheritdoc}
*/
public function installAssets(string $targetDir, int $symlinkMask): int
{
// Create the bundles directory otherwise symlink will fail.
$targetDir = rtrim($targetDir, '/') . '/bundles/';
$this->filesystem->mkdir($targetDir);
$effectiveSymlinkMask = $symlinkMask;
foreach ($this->kernel->getBundles() as $bundle) {
$effectiveSymlinkMask = min($effectiveSymlinkMask, $this->installBundleAssets($bundle, $targetDir, $symlinkMask));
}
return $effectiveSymlinkMask;
}
/**
* {@inheritdoc}
*/
public function installBundleAssets(BundleInterface $bundle, string $targetDir, int $symlinkMask): int
{
$targetDir .= preg_replace('/bundle$/', '', strtolower($bundle->getName()));
$this->filesystem->remove($targetDir);
$effectiveSymlinkMask = $symlinkMask;
foreach ($this->findAssetsPaths($bundle) as $originDir) {
$effectiveSymlinkMask = min(
$effectiveSymlinkMask,
$this->installVanillaBundleAssets($originDir, $targetDir, $symlinkMask)
);
}
foreach ($this->themeRepository->findAll() as $theme) {
$themes = $this->themeHierarchyProvider->getThemeHierarchy($theme);
foreach ($this->findAssetsPaths($bundle, $themes) as $originDir) {
$effectiveSymlinkMask = min(
$effectiveSymlinkMask,
$this->installThemedBundleAssets($theme, $originDir, $targetDir, $symlinkMask)
);
}
}
return $effectiveSymlinkMask;
}
/**
* @param ThemeInterface $theme
* @param string $originDir
* @param string $targetDir
* @param int $symlinkMask
*
* @return int
*/
private function installThemedBundleAssets(ThemeInterface $theme, string $originDir, string $targetDir, int $symlinkMask): int
{
$effectiveSymlinkMask = $symlinkMask;
$finder = new Finder();
$finder->sortByName()->ignoreDotFiles(false)->in($originDir);
/** @var SplFileInfo[] $finder */
foreach ($finder as $originFile) {
$targetFile = $targetDir . '/' . $originFile->getRelativePathname();
$targetFile = $this->pathResolver->resolve($targetFile, $theme);
if (file_exists($targetFile) && AssetsInstallerInterface::HARD_COPY !== $symlinkMask) {
continue;
}
$this->filesystem->mkdir(dirname($targetFile));
$effectiveSymlinkMask = min(
$effectiveSymlinkMask,
$this->installAsset($originFile->getPathname(), $targetFile, $symlinkMask)
);
}
return $effectiveSymlinkMask;
}
/**
* @param string $originDir
* @param string $targetDir
* @param int $symlinkMask
*
* @return int
*/
private function installVanillaBundleAssets(string $originDir, string $targetDir, int $symlinkMask): int
{
return $this->installAsset($originDir, $targetDir, $symlinkMask);
}
/**
* @param string $origin
* @param string $target
* @param int $symlinkMask
*
* @return int
*/
private function installAsset(string $origin, string $target, int $symlinkMask): int
{
if (AssetsInstallerInterface::RELATIVE_SYMLINK === $symlinkMask) {
try {
$targetDirname = realpath(is_dir($target) ? $target : dirname($target));
$relativeOrigin = rtrim($this->filesystem->makePathRelative($origin, $targetDirname), '/');
$this->doInstallAsset($relativeOrigin, $target, true);
return AssetsInstallerInterface::RELATIVE_SYMLINK;
} catch (IOException $exception) {
// Do nothing, trying to create non-relative symlinks later.
}
}
if (AssetsInstallerInterface::HARD_COPY !== $symlinkMask) {
try {
$this->doInstallAsset($origin, $target, true);
return AssetsInstallerInterface::SYMLINK;
} catch (IOException $exception) {
// Do nothing, hard copy later.
}
}
$this->doInstallAsset($origin, $target, false);
return AssetsInstallerInterface::HARD_COPY;
}
/**
* @param string $origin
* @param string $target
* @param bool $symlink
*
* @throws IOException When failed to make symbolic link, if requested.
*/
private function doInstallAsset(string $origin, string $target, bool $symlink): void
{
if ($symlink) {
$this->doSymlinkAsset($origin, $target);
return;
}
$this->doCopyAsset($origin, $target);
}
/**
* @param BundleInterface $bundle
* @param array|ThemeInterface[] $themes
*
* @return array
*/
private function findAssetsPaths(BundleInterface $bundle, array $themes = []): array
{
$sources = [];
foreach ($themes as $theme) {
$sourceDir = $theme->getPath() . '/' . $bundle->getName() . '/public';
if (is_dir($sourceDir)) {
$sources[] = $sourceDir;
}
}
$sourceDir = $bundle->getPath() . '/Resources/public';
if (is_dir($sourceDir)) {
$sources[] = $sourceDir;
}
return $sources;
}
/**
* @param string $origin
* @param string $target
*
* @throws IOException If symbolic link is broken
*/
private function doSymlinkAsset(string $origin, string $target): void
{
$this->filesystem->symlink($origin, $target);
if (!file_exists($target)) {
throw new IOException('Symbolic link is broken');
}
}
/**
* @param string $origin
* @param string $target
*/
private function doCopyAsset(string $origin, string $target): void
{
if (is_dir($origin)) {
$this->filesystem->mkdir($target, 0777);
$this->filesystem->mirror($origin, $target, Finder::create()->ignoreDotFiles(false)->in($origin));
return;
}
$this->filesystem->copy($origin, $target);
}
}

View file

@ -1,63 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Installer;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
interface AssetsInstallerInterface
{
/**
* Constant used as parameter and returned in installAssets() methods.
*
* @see AssetsInstallerInterface::installAssets()
* @see AssetsInstallerInterface::installBundleAssets()
* @see AssetsInstallerInterface::installDirAssets()
*/
public const HARD_COPY = 0;
/**
* Constant used as parameter and returned in installAssets() methods.
*
* @see AssetsInstallerInterface::installAssets()
* @see AssetsInstallerInterface::installBundleAssets()
* @see AssetsInstallerInterface::installDirAssets()
*/
public const SYMLINK = 1;
/**
* Constant used as parameter and returned in installAssets() methods.
*
* @see AssetsInstallerInterface::installAssets()
* @see AssetsInstallerInterface::installBundleAssets()
* @see AssetsInstallerInterface::installDirAssets()
*/
public const RELATIVE_SYMLINK = 2;
/**
* @param string $targetDir
* @param int $symlinkMask
*
* @return int Effective symlink mask (lowest value received from installBundleAssets() method)
*/
public function installAssets(string $targetDir, int $symlinkMask);
/**
* @param BundleInterface $bundle
* @param string $targetDir
* @param int $symlinkMask
*
* @return int Effective symlink mask (lowest value received from installDirAssets() method)
*/
public function installBundleAssets(BundleInterface $bundle, string $targetDir, int $symlinkMask);
}

View file

@ -1,120 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Installer;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
final class OutputAwareAssetsInstaller implements AssetsInstallerInterface, OutputAwareInterface
{
/**
* @var AssetsInstallerInterface
*/
private $assetsInstaller;
/**
* @var OutputInterface
*/
private $output;
/**
* @param AssetsInstallerInterface $assetsInstaller
*/
public function __construct(AssetsInstallerInterface $assetsInstaller)
{
$this->assetsInstaller = $assetsInstaller;
$this->output = new NullOutput();
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output): void
{
$this->output = $output;
}
/**
* {@inheritdoc}
*/
public function installAssets(string $targetDir, int $symlinkMask): int
{
$this->output->writeln($this->provideExpectationComment($symlinkMask));
return $this->assetsInstaller->installAssets($targetDir, $symlinkMask);
}
/**
* {@inheritdoc}
*/
public function installBundleAssets(BundleInterface $bundle, string $targetDir, int $symlinkMask): int
{
$this->output->writeln(sprintf(
'Installing assets for <comment>%s</comment> into <comment>%s</comment>',
$bundle->getNamespace(),
$targetDir
));
$effectiveSymlinkMask = $this->assetsInstaller->installBundleAssets($bundle, $targetDir, $symlinkMask);
$this->output->writeln($this->provideResultComment($symlinkMask, $effectiveSymlinkMask));
return $effectiveSymlinkMask;
}
/**
* @param int $symlinkMask
* @param int $effectiveSymlinkMask
*
* @return string
*/
private function provideResultComment(int $symlinkMask, int $effectiveSymlinkMask): string
{
if ($effectiveSymlinkMask === $symlinkMask) {
switch ($symlinkMask) {
case AssetsInstallerInterface::HARD_COPY:
return 'The assets were copied.';
case AssetsInstallerInterface::SYMLINK:
return 'The assets were installed using symbolic links.';
case AssetsInstallerInterface::RELATIVE_SYMLINK:
return 'The assets were installed using relative symbolic links.';
}
}
switch ($symlinkMask + $effectiveSymlinkMask) {
case AssetsInstallerInterface::SYMLINK:
case AssetsInstallerInterface::RELATIVE_SYMLINK:
return 'It looks like your system doesn\'t support symbolic links, so the assets were copied.';
case AssetsInstallerInterface::RELATIVE_SYMLINK + AssetsInstallerInterface::SYMLINK:
return 'It looks like your system doesn\'t support relative symbolic links, so the assets were installed by using absolute symbolic links.';
}
return 'Something gone bad, can\'t provide the result of assets installing!';
}
/**
* @param int $symlinkMask
*
* @return string
*/
private function provideExpectationComment(int $symlinkMask): string
{
if (AssetsInstallerInterface::HARD_COPY === $symlinkMask) {
return 'Installing assets as <comment>hard copies</comment>.';
}
return 'Trying to install assets as <comment>symbolic links</comment>.';
}
}

View file

@ -1,24 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Installer;
use Symfony\Component\Console\Output\OutputInterface;
interface OutputAwareInterface
{
/**
* @param OutputInterface $output
*/
public function setOutput(OutputInterface $output): void;
}

View file

@ -1,80 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Package;
use Sylius\Bundle\ThemeBundle\Asset\PathResolverInterface;
use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
use Symfony\Component\Asset\Context\ContextInterface;
use Symfony\Component\Asset\PathPackage as BasePathPackage;
use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;
/**
* @see BasePathPackage
*/
class PathPackage extends BasePathPackage
{
/**
* @var ThemeContextInterface
*/
protected $themeContext;
/**
* @var PathResolverInterface
*/
protected $pathResolver;
/**
* @param string $basePath
* @param VersionStrategyInterface $versionStrategy
* @param ThemeContextInterface $themeContext
* @param PathResolverInterface $pathResolver
* @param ContextInterface|null $context
*/
public function __construct(
string $basePath,
VersionStrategyInterface $versionStrategy,
ThemeContextInterface $themeContext,
PathResolverInterface $pathResolver,
?ContextInterface $context = null
) {
parent::__construct($basePath, $versionStrategy, $context);
$this->themeContext = $themeContext;
$this->pathResolver = $pathResolver;
}
/**
* {@inheritdoc}
*/
public function getUrl($path): string
{
if ($this->isAbsoluteUrl($path)) {
return $path;
}
$theme = $this->themeContext->getTheme();
if (null !== $theme) {
$path = $this->pathResolver->resolve($path, $theme);
}
$versionedPath = $this->getVersionStrategy()->applyVersion($path);
// if absolute or begins with /, we're done
if ($this->isAbsoluteUrl($versionedPath) || ($versionedPath && '/' === $versionedPath[0])) {
return $versionedPath;
}
return $this->getBasePath() . ltrim($versionedPath, '/');
}
}

View file

@ -1,132 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset\Package;
use Sylius\Bundle\ThemeBundle\Asset\PathResolverInterface;
use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
use Symfony\Component\Asset\Context\ContextInterface;
use Symfony\Component\Asset\Exception\InvalidArgumentException;
use Symfony\Component\Asset\UrlPackage as BaseUrlPackage;
use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;
/**
* @see BaseUrlPackage
*/
class UrlPackage extends BaseUrlPackage
{
/**
* @var array
*/
private $baseUrls = [];
/**
* @var UrlPackage
*/
private $sslPackage;
/**
* @var ThemeContextInterface
*/
protected $themeContext;
/**
* @var PathResolverInterface
*/
protected $pathResolver;
/**
* @param string|array $baseUrls Base asset URLs
* @param VersionStrategyInterface $versionStrategy The version strategy
* @param ThemeContextInterface $themeContext
* @param PathResolverInterface $pathResolver
* @param ContextInterface|null $context Context
*/
public function __construct(
$baseUrls,
VersionStrategyInterface $versionStrategy,
ThemeContextInterface $themeContext,
PathResolverInterface $pathResolver,
?ContextInterface $context = null
) {
parent::__construct($baseUrls, $versionStrategy, $context);
if (!is_array($baseUrls)) {
$baseUrls = (array) $baseUrls;
}
foreach ($baseUrls as $baseUrl) {
$this->baseUrls[] = rtrim($baseUrl, '/');
}
$sslUrls = $this->getSslUrls($baseUrls);
if ($sslUrls && $baseUrls !== $sslUrls) {
$this->sslPackage = new self($sslUrls, $versionStrategy, $themeContext, $pathResolver);
}
$this->themeContext = $themeContext;
$this->pathResolver = $pathResolver;
}
/**
* {@inheritdoc}
*/
public function getUrl($path): string
{
if ($this->isAbsoluteUrl($path)) {
return $path;
}
if (null !== $this->sslPackage && $this->getContext()->isSecure()) {
return $this->sslPackage->getUrl($path);
}
$theme = $this->themeContext->getTheme();
if (null !== $theme) {
$path = $this->pathResolver->resolve($path, $theme);
}
$url = $this->getVersionStrategy()->applyVersion($path);
if ($this->isAbsoluteUrl($url)) {
return $url;
}
if ($url && '/' != $url[0]) {
$url = '/' . $url;
}
return $this->getBaseUrl($path) . $url;
}
/**
* @param array $urls
*
* @return array
*/
private function getSslUrls(array $urls): array
{
$sslUrls = [];
foreach ($urls as $url) {
if ('https://' === substr($url, 0, 8) || '//' === substr($url, 0, 2)) {
$sslUrls[] = $url;
} elseif ('http://' !== substr($url, 0, 7)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid URL', $url));
}
}
return $sslUrls;
}
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class PathResolver implements PathResolverInterface
{
/**
* {@inheritdoc}
*/
public function resolve(string $path, ThemeInterface $theme): string
{
return str_replace('bundles/', 'bundles/_themes/' . $theme->getName() . '/', $path);
}
}

View file

@ -1,30 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Asset;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface PathResolverInterface
{
/**
* Applies theme hashcode to given asset file in order to distinguish it from
* another same named assets files with another theme or without it.
*
* @param string $path
* @param ThemeInterface $theme
*
* @return string
*/
public function resolve(string $path, ThemeInterface $theme): string;
}

View file

@ -1,115 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Collector;
use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
use Sylius\Bundle\ThemeBundle\HierarchyProvider\ThemeHierarchyProviderInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
final class ThemeCollector extends DataCollector
{
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @var ThemeContextInterface
*/
private $themeContext;
/**
* @var ThemeHierarchyProviderInterface
*/
private $themeHierarchyProvider;
/**
* @param ThemeRepositoryInterface $themeRepository
* @param ThemeContextInterface $themeContext
* @param ThemeHierarchyProviderInterface $themeHierarchyProvider
*/
public function __construct(
ThemeRepositoryInterface $themeRepository,
ThemeContextInterface $themeContext,
ThemeHierarchyProviderInterface $themeHierarchyProvider
) {
$this->themeRepository = $themeRepository;
$this->themeContext = $themeContext;
$this->themeHierarchyProvider = $themeHierarchyProvider;
$this->data = [
'used_theme' => null,
'used_themes' => [],
'themes' => [],
];
}
/**
* @return ThemeInterface|null
*/
public function getUsedTheme(): ?ThemeInterface
{
return $this->data['used_theme'];
}
/**
* @return array|ThemeInterface[]
*/
public function getUsedThemes(): array
{
return $this->data['used_themes'];
}
/**
* @return ThemeInterface[]
*/
public function getThemes(): array
{
return $this->data['themes'];
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, ?\Exception $exception = null): void
{
$usedTheme = $this->themeContext->getTheme();
$this->data['used_theme'] = $usedTheme;
$this->data['used_themes'] = null !== $usedTheme ? $this->themeHierarchyProvider->getThemeHierarchy($usedTheme) : [];
$this->data['themes'] = $this->themeRepository->findAll();
}
/**
* {@inheritdoc}
*/
public function reset(): void
{
$this->data['used_theme'] = null;
$this->data['used_themes'] = [];
$this->data['themes'] = [];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'sylius_theme';
}
}

View file

@ -1,95 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Command;
use Sylius\Bundle\ThemeBundle\Asset\Installer\AssetsInstallerInterface;
use Sylius\Bundle\ThemeBundle\Asset\Installer\OutputAwareInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Command that places themes web assets into a given directory.
*/
final class AssetsInstallCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
->setName('sylius:theme:assets:install')
->setDefinition([
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', 'web'),
])
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlinks the assets instead of copying it')
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
->setDescription('Installs themes web assets under a public web directory')
->setHelp($this->getHelpMessage())
;
}
/**
* {@inheritdoc}
*
* @throws \InvalidArgumentException When the target directory does not exist or symlink cannot be used
*/
protected function execute(InputInterface $input, OutputInterface $output): void
{
$assetsInstaller = $this->getContainer()->get('sylius.theme.asset.assets_installer');
if ($assetsInstaller instanceof OutputAwareInterface) {
$assetsInstaller->setOutput($output);
}
$symlinkMask = AssetsInstallerInterface::HARD_COPY;
if ($input->getOption('symlink')) {
$symlinkMask = max($symlinkMask, AssetsInstallerInterface::SYMLINK);
}
if ($input->getOption('relative')) {
$symlinkMask = max($symlinkMask, AssetsInstallerInterface::RELATIVE_SYMLINK);
}
$assetsInstaller->installAssets($input->getArgument('target'), $symlinkMask);
}
/**
* @return string
*/
private function getHelpMessage(): string
{
return <<<EOT
The <info>%command.name%</info> command installs theme assets into a given
directory (e.g. the <comment>web</comment> directory).
<info>php %command.full_name% web</info>
A "themes" directory will be created inside the target directory.
To create a symlink to each theme instead of copying its assets, use the
<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible):
<info>php %command.full_name% web --symlink</info>
To make symlink relative, add the <info>--relative</info> option:
<info>php %command.full_name% web --symlink --relative</info>
EOT;
}
}

View file

@ -1,61 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Command;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class ListCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
->setName('sylius:theme:list')
->setDescription('Shows list of detected themes.')
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): void
{
/** @var ThemeInterface[] $themes */
$themes = $this->getContainer()->get('sylius.repository.theme')->findAll();
if (0 === count($themes)) {
$output->writeln('<error>There are no themes.</error>');
return;
}
$output->writeln('<question>Successfully loaded themes:</question>');
$table = new Table($output);
$table->setHeaders(['Title', 'Name', 'Path']);
foreach ($themes as $theme) {
$table->addRow([$theme->getTitle(), $theme->getName(), $theme->getPath()]);
}
$table->setStyle('borderless');
$table->render();
}
}

View file

@ -1,46 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
final class CompositeConfigurationProvider implements ConfigurationProviderInterface
{
/**
* @var ConfigurationProviderInterface[]
*/
private $configurationProviders;
/**
* @param ConfigurationProviderInterface[] $configurationProviders
*/
public function __construct(array $configurationProviders)
{
$this->configurationProviders = $configurationProviders;
}
/**
* {@inheritdoc}
*/
public function getConfigurations(): array
{
$configurations = [];
foreach ($this->configurationProviders as $configurationProvider) {
$configurations = array_merge(
$configurations,
$configurationProvider->getConfigurations()
);
}
return $configurations;
}
}

View file

@ -1,24 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
interface ConfigurationProcessorInterface
{
/**
* @param array $configs An array of configuration arrays
*
* @return array The processed configuration array
*/
public function process(array $configs): array;
}

View file

@ -1,22 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
interface ConfigurationProviderInterface
{
/**
* @return array
*/
public function getConfigurations(): array;
}

View file

@ -1,42 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
interface ConfigurationSourceFactoryInterface
{
/**
* @param ArrayNodeDefinition $node
*/
public function buildConfiguration(ArrayNodeDefinition $node): void;
/**
* @see ConfigurationProviderInterface
*
* @param ContainerBuilder $container
* @param array $config
*
* @return Reference|Definition Configuration provider service
*/
public function initializeSource(ContainerBuilder $container, array $config);
/**
* @return string
*/
public function getName(): string;
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Filesystem;
interface ConfigurationLoaderInterface
{
/**
* Loads configuration for given identifier (can be theme name or path to configuration file)
*
* @param string $identifier
*
* @return array
*/
public function load(string $identifier): array;
}

View file

@ -1,62 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Filesystem;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationProviderInterface;
use Sylius\Bundle\ThemeBundle\Locator\FileLocatorInterface;
final class FilesystemConfigurationProvider implements ConfigurationProviderInterface
{
/**
* @var FileLocatorInterface
*/
private $fileLocator;
/**
* @var ConfigurationLoaderInterface
*/
private $loader;
/**
* @var string
*/
private $configurationFilename;
/**
* @param FileLocatorInterface $fileLocator
* @param ConfigurationLoaderInterface $loader
* @param string $configurationFilename
*/
public function __construct(FileLocatorInterface $fileLocator, ConfigurationLoaderInterface $loader, $configurationFilename)
{
$this->fileLocator = $fileLocator;
$this->loader = $loader;
$this->configurationFilename = $configurationFilename;
}
/**
* {@inheritdoc}
*/
public function getConfigurations(): array
{
try {
return array_map(
[$this->loader, 'load'],
$this->fileLocator->locateFilesNamed($this->configurationFilename)
);
} catch (\InvalidArgumentException $exception) {
return [];
}
}
}

View file

@ -1,78 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Filesystem;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationSourceFactoryInterface;
use Sylius\Bundle\ThemeBundle\Locator\RecursiveFileLocator;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
final class FilesystemConfigurationSourceFactory implements ConfigurationSourceFactoryInterface
{
/**
* {@inheritdoc}
*/
public function buildConfiguration(ArrayNodeDefinition $node): void
{
$node
->fixXmlConfig('directory', 'directories')
->children()
->scalarNode('filename')->defaultValue('composer.json')->cannotBeEmpty()->end()
->integerNode('scan_depth')->info('Restrict depth to scan for configuration file inside theme folder')->defaultNull()->end()
->arrayNode('directories')
->defaultValue(['%kernel.root_dir%/themes'])
->requiresAtLeastOneElement()
->performNoDeepMerging()
->prototype('scalar')
->end()
;
}
/**
* {@inheritdoc}
*/
public function initializeSource(ContainerBuilder $container, array $config): Definition
{
$recursiveFileLocator = new Definition(RecursiveFileLocator::class, [
new Reference('sylius.theme.finder_factory'),
$config['directories'],
$config['scan_depth'],
]);
$configurationLoader = new Definition(ProcessingConfigurationLoader::class, [
new Definition(JsonFileConfigurationLoader::class, [
new Reference('sylius.theme.filesystem'),
]),
new Reference('sylius.theme.configuration.processor'),
]);
$configurationProvider = new Definition(FilesystemConfigurationProvider::class, [
$recursiveFileLocator,
$configurationLoader,
$config['filename'],
]);
return $configurationProvider;
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'filesystem';
}
}

View file

@ -1,60 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Filesystem;
use Sylius\Bundle\ThemeBundle\Filesystem\FilesystemInterface;
final class JsonFileConfigurationLoader implements ConfigurationLoaderInterface
{
/**
* @var FilesystemInterface
*/
private $filesystem;
/**
* @param FilesystemInterface $filesystem
*/
public function __construct(FilesystemInterface $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* {@inheritdoc}
*/
public function load(string $identifier): array
{
$this->assertFileExists($identifier);
$contents = $this->filesystem->getFileContents($identifier);
return array_merge(
['path' => dirname($identifier)],
json_decode($contents, true)
);
}
/**
* @param string $path
*/
private function assertFileExists(string $path): void
{
if (!$this->filesystem->exists($path)) {
throw new \InvalidArgumentException(sprintf(
'Given file "%s" does not exist!',
$path
));
}
}
}

View file

@ -1,54 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Filesystem;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationProcessorInterface;
final class ProcessingConfigurationLoader implements ConfigurationLoaderInterface
{
/**
* @var ConfigurationLoaderInterface
*/
private $decoratedLoader;
/**
* @var ConfigurationProcessorInterface
*/
private $configurationProcessor;
/**
* @param ConfigurationLoaderInterface $decoratedLoader
* @param ConfigurationProcessorInterface $configurationProcessor
*/
public function __construct(ConfigurationLoaderInterface $decoratedLoader, ConfigurationProcessorInterface $configurationProcessor)
{
$this->decoratedLoader = $decoratedLoader;
$this->configurationProcessor = $configurationProcessor;
}
/**
* {@inheritdoc}
*/
public function load(string $identifier): array
{
$rawConfiguration = $this->decoratedLoader->load($identifier);
$configurations = [$rawConfiguration];
if (isset($rawConfiguration['extra']['sylius-theme'])) {
$configurations[] = $rawConfiguration['extra']['sylius-theme'];
}
return $this->configurationProcessor->process($configurations);
}
}

View file

@ -1,48 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
final class SymfonyConfigurationProcessor implements ConfigurationProcessorInterface
{
/**
* @var ConfigurationInterface
*/
private $configuration;
/**
* @var Processor
*/
private $processor;
/**
* @param ConfigurationInterface $configuration
* @param Processor $processor
*/
public function __construct(ConfigurationInterface $configuration, Processor $processor)
{
$this->configuration = $configuration;
$this->processor = $processor;
}
/**
* {@inheritdoc}
*/
public function process(array $configs): array
{
return $this->processor->processConfiguration($this->configuration, $configs);
}
}

View file

@ -1,40 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Test;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationProviderInterface;
final class TestConfigurationProvider implements ConfigurationProviderInterface
{
/**
* @var TestThemeConfigurationManagerInterface
*/
private $testThemeConfigurationManager;
/**
* @param TestThemeConfigurationManagerInterface $testThemeConfigurationManager
*/
public function __construct(TestThemeConfigurationManagerInterface $testThemeConfigurationManager)
{
$this->testThemeConfigurationManager = $testThemeConfigurationManager;
}
/**
* {@inheritdoc}
*/
public function getConfigurations(): array
{
return $this->testThemeConfigurationManager->findAll();
}
}

View file

@ -1,58 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Test;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationSourceFactoryInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
final class TestConfigurationSourceFactory implements ConfigurationSourceFactoryInterface
{
/**
* {@inheritdoc}
*/
public function buildConfiguration(ArrayNodeDefinition $node): void
{
// no configuration
}
/**
* {@inheritdoc}
*/
public function initializeSource(ContainerBuilder $container, array $config): Definition
{
$container->setDefinition(
'sylius.theme.test_theme_configuration_manager',
new Definition(TestThemeConfigurationManager::class, [
new Reference('sylius.theme.configuration.processor'),
new Parameter('kernel.cache_dir'),
])
);
return new Definition(TestConfigurationProvider::class, [
new Reference('sylius.theme.test_theme_configuration_manager'),
]);
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'test';
}
}

View file

@ -1,169 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Test;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationProcessorInterface;
use Symfony\Component\Filesystem\Filesystem;
final class TestThemeConfigurationManager implements TestThemeConfigurationManagerInterface
{
/**
* @var ConfigurationProcessorInterface
*/
private $configurationProcessor;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var string
*/
private $configurationsFile;
/**
* @param ConfigurationProcessorInterface $configurationProcessor
* @param string $cacheDir
*/
public function __construct(ConfigurationProcessorInterface $configurationProcessor, string $cacheDir)
{
$this->configurationProcessor = $configurationProcessor;
$this->filesystem = new Filesystem();
$this->configurationsFile = rtrim($cacheDir, '/') . '/_test_themes/data.serialized';
}
/**
* {@inheritdoc}
*/
public function findAll(): array
{
$this->initializeIfNeeded();
return $this->load();
}
/**
* {@inheritdoc}
*/
public function add(array $configuration): void
{
$this->initializeIfNeeded();
$configuration = $this->configurationProcessor->process([$configuration]);
$configuration['path'] = $this->getThemeDirectory($configuration['name']);
$this->initializeTheme($configuration['name']);
$configurations = $this->load();
$configurations[] = $configuration;
$this->save($configurations);
}
/**
* {@inheritdoc}
*/
public function remove(string $themeName): void
{
$this->initializeIfNeeded();
$this->clearTheme($themeName);
$configurations = $this->load();
$configurations = array_filter($configurations, function ($configuration) use ($themeName) {
return isset($configuration['name']) && $configuration['name'] !== $themeName;
});
$this->save($configurations);
}
/**
* {@inheritdoc}
*/
public function clear(): void
{
$configurationsDirectory = dirname($this->configurationsFile);
if ($this->filesystem->exists($configurationsDirectory)) {
$this->filesystem->remove($configurationsDirectory);
}
}
/**
* @return array
*/
private function load(): array
{
return unserialize(file_get_contents($this->configurationsFile));
}
/**
* @param array $configurations
*/
private function save(array $configurations): void
{
file_put_contents($this->configurationsFile, serialize($configurations));
}
private function initializeIfNeeded(): void
{
if ($this->filesystem->exists($this->configurationsFile)) {
return;
}
$this->initialize();
}
private function initialize(): void
{
$configurationsDirectory = dirname($this->configurationsFile);
$this->filesystem->mkdir($configurationsDirectory);
$this->save([]);
}
/**
* @param string $themeName
*/
private function initializeTheme(string $themeName): void
{
$themeDirectory = $this->getThemeDirectory($themeName);
$this->filesystem->mkdir($themeDirectory);
}
/**
* @param string $themeName
*/
private function clearTheme(string $themeName): void
{
$themeDirectory = $this->getThemeDirectory($themeName);
if (!$this->filesystem->exists($themeDirectory)) {
return;
}
$this->filesystem->remove($themeDirectory);
}
/**
* @param string $themeName
*
* @return string
*/
private function getThemeDirectory(string $themeName): string
{
return rtrim(dirname($this->configurationsFile), '/') . '/' . $themeName;
}
}

View file

@ -1,37 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration\Test;
interface TestThemeConfigurationManagerInterface
{
/**
* @return array
*/
public function findAll(): array;
/**
* @param array $configuration
*/
public function add(array $configuration): void;
/**
* @param string $themeName
*/
public function remove(string $themeName): void;
/**
* Clear currently used configurations storage.
*/
public function clear(): void;
}

View file

@ -1,152 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Configuration;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class ThemeConfiguration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder();
/** @var ArrayNodeDefinition $rootNodeDefinition */
$rootNodeDefinition = $treeBuilder->root('sylius_theme');
$rootNodeDefinition->ignoreExtraKeys();
$this->addRequiredNameField($rootNodeDefinition);
$this->addOptionalTitleField($rootNodeDefinition);
$this->addOptionalDescriptionField($rootNodeDefinition);
$this->addOptionalPathField($rootNodeDefinition);
$this->addOptionalParentsList($rootNodeDefinition);
$this->addOptionalScreenshotsList($rootNodeDefinition);
$this->addOptionalAuthorsList($rootNodeDefinition);
return $treeBuilder;
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addRequiredNameField(ArrayNodeDefinition $rootNodeDefinition): void
{
$rootNodeDefinition->children()->scalarNode('name')->isRequired()->cannotBeEmpty();
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalTitleField(ArrayNodeDefinition $rootNodeDefinition): void
{
$rootNodeDefinition->children()->scalarNode('title')->cannotBeEmpty();
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalDescriptionField(ArrayNodeDefinition $rootNodeDefinition): void
{
$rootNodeDefinition->children()->scalarNode('description')->cannotBeEmpty();
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalPathField(ArrayNodeDefinition $rootNodeDefinition): void
{
$rootNodeDefinition->children()->scalarNode('path')->cannotBeEmpty();
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalParentsList(ArrayNodeDefinition $rootNodeDefinition): void
{
$parentsNodeDefinition = $rootNodeDefinition->children()->arrayNode('parents');
$parentsNodeDefinition
->requiresAtLeastOneElement()
->performNoDeepMerging()
->scalarPrototype()
->cannotBeEmpty()
;
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalScreenshotsList(ArrayNodeDefinition $rootNodeDefinition): void
{
$screenshotsNodeDefinition = $rootNodeDefinition->children()->arrayNode('screenshots');
$screenshotsNodeDefinition
->requiresAtLeastOneElement()
->performNoDeepMerging()
;
/** @var ArrayNodeDefinition $screenshotNodeDefinition */
$screenshotNodeDefinition = $screenshotsNodeDefinition->arrayPrototype();
$screenshotNodeDefinition
->validate()
->ifTrue(function ($screenshot) {
return [] === $screenshot || ['path' => ''] === $screenshot;
})
->thenInvalid('Screenshot cannot be empty!')
;
$screenshotNodeDefinition
->beforeNormalization()
->ifString()
->then(function ($value) {
return ['path' => $value];
})
;
$screenshotNodeBuilder = $screenshotNodeDefinition->children();
$screenshotNodeBuilder->scalarNode('path')->isRequired();
$screenshotNodeBuilder->scalarNode('title')->cannotBeEmpty();
$screenshotNodeBuilder->scalarNode('description')->cannotBeEmpty();
}
/**
* @param ArrayNodeDefinition $rootNodeDefinition
*/
private function addOptionalAuthorsList(ArrayNodeDefinition $rootNodeDefinition): void
{
$authorsNodeDefinition = $rootNodeDefinition->children()->arrayNode('authors');
$authorsNodeDefinition
->requiresAtLeastOneElement()
->performNoDeepMerging()
;
/** @var ArrayNodeDefinition $authorNodeDefinition */
$authorNodeDefinition = $authorsNodeDefinition->arrayPrototype();
$authorNodeDefinition
->validate()
->ifTrue(function ($author) {
return [] === $author;
})
->thenInvalid('Author cannot be empty!')
;
$authorNodeBuilder = $authorNodeDefinition->children();
$authorNodeBuilder->scalarNode('name')->cannotBeEmpty();
$authorNodeBuilder->scalarNode('email')->cannotBeEmpty();
$authorNodeBuilder->scalarNode('homepage')->cannotBeEmpty();
$authorNodeBuilder->scalarNode('role')->cannotBeEmpty();
}
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Context;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class EmptyThemeContext implements ThemeContextInterface
{
/**
* {@inheritdoc}
*/
public function getTheme(): ?ThemeInterface
{
return null;
}
}

View file

@ -1,40 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Context;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class SettableThemeContext implements ThemeContextInterface
{
/**
* @var ThemeInterface
*/
private $theme;
/**
* {@inheritdoc}
*/
public function setTheme(ThemeInterface $theme): void
{
$this->theme = $theme;
}
/**
* {@inheritdoc}
*/
public function getTheme(): ?ThemeInterface
{
return $this->theme;
}
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Context;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ThemeContextInterface
{
/**
* Should not throw any exception if failed to get theme.
*
* @return ThemeInterface|null
*/
public function getTheme(): ?ThemeInterface;
}

View file

@ -1,88 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Controller;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
final class ThemeScreenshotController
{
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @param ThemeRepositoryInterface $themeRepository
*/
public function __construct(ThemeRepositoryInterface $themeRepository)
{
$this->themeRepository = $themeRepository;
}
/**
* @param string $themeName
* @param int $screenshotNumber
*
* @return Response
*/
public function streamScreenshotAction(string $themeName, int $screenshotNumber): Response
{
$screenshotPath = $this->getScreenshotPath($this->getTheme($themeName), $screenshotNumber);
try {
return new BinaryFileResponse($screenshotPath);
} catch (FileNotFoundException $exception) {
throw new NotFoundHttpException(sprintf('Screenshot "%s" does not exist', $screenshotPath), $exception);
}
}
/**
* @param ThemeInterface $theme
* @param int $screenshotNumber
*
* @return string
*/
private function getScreenshotPath(ThemeInterface $theme, int $screenshotNumber): string
{
$screenshots = $theme->getScreenshots();
if (!isset($screenshots[$screenshotNumber])) {
throw new NotFoundHttpException(sprintf('Theme "%s" does not have screenshot #%d', $theme->getTitle(), $screenshotNumber));
}
$screenshotRelativePath = $screenshots[$screenshotNumber]->getPath();
return rtrim($theme->getPath(), \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR . $screenshotRelativePath;
}
/**
* @param string $themeName
*
* @return ThemeInterface
*/
private function getTheme(string $themeName): ThemeInterface
{
$theme = $this->themeRepository->findOneByName($themeName);
if (null === $theme) {
throw new NotFoundHttpException(sprintf('Theme with name "%s" not found', $themeName));
}
return $theme;
}
}

View file

@ -1,87 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\DependencyInjection;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationSourceFactoryInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class Configuration implements ConfigurationInterface
{
/**
* @var ConfigurationSourceFactoryInterface[]
*/
private $configurationSourceFactories;
/**
* @param ConfigurationSourceFactoryInterface[] $configurationSourceFactories
*/
public function __construct(array $configurationSourceFactories = [])
{
$this->configurationSourceFactories = $configurationSourceFactories;
}
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('sylius_theme');
$this->addSourcesConfiguration($rootNode);
$rootNode
->children()
->arrayNode('assets')
->canBeDisabled()
->end()
->arrayNode('templating')
->canBeDisabled()
->end()
->arrayNode('translations')
->canBeDisabled()
->end()
->scalarNode('context')
->defaultValue('sylius.theme.context.settable')
->cannotBeEmpty()
->end()
;
return $treeBuilder;
}
/**
* @param ArrayNodeDefinition $rootNode
*/
private function addSourcesConfiguration(ArrayNodeDefinition $rootNode): void
{
$sourcesNodeBuilder = $rootNode
->fixXmlConfig('source')
->children()
->arrayNode('sources')
->children()
;
foreach ($this->configurationSourceFactories as $sourceFactory) {
$sourceNode = $sourcesNodeBuilder
->arrayNode($sourceFactory->getName())
->canBeEnabled()
;
$sourceFactory->buildConfiguration($sourceNode);
}
}
}

View file

@ -1,143 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\DependencyInjection;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationSourceFactoryInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
final class SyliusThemeExtension extends Extension implements PrependExtensionInterface
{
/**
* @var ConfigurationSourceFactoryInterface[]
*/
private $configurationSourceFactories = [];
/**
* @internal
*
* {@inheritdoc}
*/
public function load(array $config, ContainerBuilder $container): void
{
$config = $this->processConfiguration($this->getConfiguration([], $container), $config);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.xml');
if ($config['assets']['enabled']) {
$loader->load('services/integrations/assets.xml');
}
if ($config['templating']['enabled']) {
$loader->load('services/integrations/templating.xml');
}
if ($config['translations']['enabled']) {
$loader->load('services/integrations/translations.xml');
}
$this->resolveConfigurationSources($container, $config);
$container->setAlias('sylius.context.theme', $config['context']);
}
/**
* @internal
*
* {@inheritdoc}
*/
public function prepend(ContainerBuilder $container): void
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$this->prependTwig($container, $loader);
}
/**
* @api
*
* @param ConfigurationSourceFactoryInterface $configurationSourceFactory
*/
public function addConfigurationSourceFactory(ConfigurationSourceFactoryInterface $configurationSourceFactory): void
{
$this->configurationSourceFactories[$configurationSourceFactory->getName()] = $configurationSourceFactory;
}
/**
* {@inheritdoc}
*/
public function getConfiguration(array $config, ContainerBuilder $container): Configuration
{
$configuration = new Configuration($this->configurationSourceFactories);
$container->addObjectResource($configuration);
return $configuration;
}
/**
* @param ContainerBuilder $container
* @param LoaderInterface $loader
*/
private function prependTwig(ContainerBuilder $container, LoaderInterface $loader): void
{
if (!$container->hasExtension('twig')) {
return;
}
$loader->load('services/integrations/twig.xml');
}
/**
* @param ContainerBuilder $container
* @param array $config
*/
private function resolveConfigurationSources(ContainerBuilder $container, array $config): void
{
$configurationProviders = [];
foreach ($this->configurationSourceFactories as $configurationSourceFactory) {
$sourceName = $configurationSourceFactory->getName();
if (isset($config['sources'][$sourceName]) && $config['sources'][$sourceName]['enabled']) {
$sourceConfig = $config['sources'][$sourceName];
$configurationProvider = $configurationSourceFactory->initializeSource($container, $sourceConfig);
if (!$configurationProvider instanceof Reference && !$configurationProvider instanceof Definition) {
throw new \InvalidArgumentException(sprintf(
'Source factory "%s" was expected to return an instance of "%s" or "%s", "%s" found',
$configurationSourceFactory->getName(),
Reference::class,
Definition::class,
is_object($configurationProvider) ? get_class($configurationProvider) : gettype($configurationProvider)
));
}
$configurationProviders[] = $configurationProvider;
}
}
$compositeConfigurationProvider = $container->getDefinition('sylius.theme.configuration.provider');
$compositeConfigurationProvider->replaceArgument(0, $configurationProviders);
foreach ($this->configurationSourceFactories as $configurationSourceFactory) {
$container->addObjectResource($configurationSourceFactory);
}
}
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Symfony\Component\Finder\Finder;
final class FinderFactory implements FinderFactoryInterface
{
/**
* {@inheritdoc}
*/
public function create(): Finder
{
return Finder::create();
}
}

View file

@ -1,24 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Symfony\Component\Finder\Finder;
interface FinderFactoryInterface
{
/**
* @return Finder
*/
public function create(): Finder;
}

View file

@ -1,35 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\ThemeAuthor;
final class ThemeAuthorFactory implements ThemeAuthorFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createFromArray(array $data): ThemeAuthor
{
/** @var ThemeAuthor $author */
$author = new ThemeAuthor();
$author->setName($data['name'] ?? null);
$author->setEmail($data['email'] ?? null);
$author->setHomepage($data['homepage'] ?? null);
$author->setRole($data['role'] ?? null);
return $author;
}
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\ThemeAuthor;
interface ThemeAuthorFactoryInterface
{
/**
* @param array $data
*
* @return ThemeAuthor
*/
public function createFromArray(array $data): ThemeAuthor;
}

View file

@ -1,28 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\Theme;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class ThemeFactory implements ThemeFactoryInterface
{
/**
* {@inheritdoc}
*/
public function create(string $name, string $path): ThemeInterface
{
return new Theme($name, $path);
}
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ThemeFactoryInterface
{
/**
* @param string $name
* @param string $path
*
* @return ThemeInterface
*/
public function create(string $name, string $path): ThemeInterface;
}

View file

@ -1,35 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\ThemeScreenshot;
final class ThemeScreenshotFactory implements ThemeScreenshotFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createFromArray(array $data): ThemeScreenshot
{
if (!array_key_exists('path', $data)) {
throw new \InvalidArgumentException('Screenshot path is required.');
}
$themeScreenshot = new ThemeScreenshot($data['path']);
$themeScreenshot->setTitle($data['title'] ?? null);
$themeScreenshot->setDescription($data['description'] ?? null);
return $themeScreenshot;
}
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Factory;
use Sylius\Bundle\ThemeBundle\Model\ThemeScreenshot;
interface ThemeScreenshotFactoryInterface
{
/**
* @param array $data
*
* @return ThemeScreenshot
*/
public function createFromArray(array $data): ThemeScreenshot;
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Filesystem;
use Symfony\Component\Filesystem\Filesystem as BaseFilesystem;
final class Filesystem extends BaseFilesystem implements FilesystemInterface
{
/**
* {@inheritdoc}
*/
public function getFileContents(string $file): string
{
return file_get_contents($file);
}
}

View file

@ -1,174 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Filesystem;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\Filesystem\Exception\IOException;
interface FilesystemInterface
{
/**
* Copies a file.
*
* This method only copies the file if the origin file is newer than the target file.
*
* By default, if the target already exists, it is not overridden.
*
* @param string $originFile The original filename
* @param string $targetFile The target filename
* @param bool $override Whether to override an existing file or not
*
* @throws FileNotFoundException When originFile doesn't exist
* @throws IOException When copy fails
*/
public function copy($originFile, $targetFile, $override = false);
/**
* Creates a directory recursively.
*
* @param string|array|\Traversable $dirs The directory path
* @param int $mode The directory mode
*
* @throws IOException On any directory creation failure
*/
public function mkdir($dirs, $mode = 0777);
/**
* Checks the existence of files or directories.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check
*
* @return bool true if the file exists, false otherwise
*/
public function exists($files);
/**
* Sets access and modification time of file.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
* @param int $time The touch time as a Unix timestamp
* @param int $atime The access time as a Unix timestamp
*
* @throws IOException When touch fails
*/
public function touch($files, $time = null, $atime = null);
/**
* Removes files or directories.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
*
* @throws IOException When removal fails
*/
public function remove($files);
/**
* Change mode for an array of files or directories.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
* @param int $mode The new mode (octal)
* @param int $umask The mode mask (octal)
* @param bool $recursive Whether change the mod recursively or not
*
* @throws IOException When the change fail
*/
public function chmod($files, $mode, $umask = 0000, $recursive = false);
/**
* Change the owner of an array of files or directories.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner
* @param string $user The new owner user name
* @param bool $recursive Whether change the owner recursively or not
*
* @throws IOException When the change fail
*/
public function chown($files, $user, $recursive = false);
/**
* Change the group of an array of files or directories.
*
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group
* @param string $group The group name
* @param bool $recursive Whether change the group recursively or not
*
* @throws IOException When the change fail
*/
public function chgrp($files, $group, $recursive = false);
/**
* Renames a file or a directory.
*
* @param string $origin The origin filename or directory
* @param string $target The new filename or directory
* @param bool $overwrite Whether to overwrite the target if it already exists
*
* @throws IOException When target file or directory already exists
* @throws IOException When origin cannot be renamed
*/
public function rename($origin, $target, $overwrite = false);
/**
* Creates a symbolic link or copy a directory.
*
* @param string $originDir The origin directory path
* @param string $targetDir The symbolic link name
* @param bool $copyOnWindows Whether to copy files if on Windows
*
* @throws IOException When symlink fails
*/
public function symlink($originDir, $targetDir, $copyOnWindows = false);
/**
* Mirrors a directory to another.
*
* @param string $originDir The origin directory
* @param string $targetDir The target directory
* @param \Traversable $iterator A Traversable instance
* @param array $options An array of boolean options
* Valid options are:
* - $options['override'] Whether to override an existing file on copy or not (see copy())
* - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
* - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
*
* @throws IOException When file type is unknown
*/
public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = []);
/**
* Given an existing path, convert it to a path relative to a given starting path.
*
* @param string $endPath Absolute path of target
* @param string $startPath Absolute path where traversal begins
*
* @return string Path of target relative to starting path
*/
public function makePathRelative($endPath, $startPath);
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return bool
*/
public function isAbsolutePath($file);
/**
* @param string $file
*
* @return string
*/
public function getFileContents(string $file): string;
}

View file

@ -1,68 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Form\Type;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class ThemeChoiceType extends AbstractType
{
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @param ThemeRepositoryInterface $themeRepository
*/
public function __construct(ThemeRepositoryInterface $themeRepository)
{
$this->themeRepository = $themeRepository;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'choices' => function (Options $options): array {
return $this->themeRepository->findAll();
},
'choice_label' => function (ThemeInterface $theme): string {
return $theme->getTitle() ?: $theme->getName();
},
]);
}
/**
* {@inheritdoc}
*/
public function getParent(): string
{
return ChoiceType::class;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'sylius_theme_choice';
}
}

View file

@ -1,71 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Form\Type;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class ThemeNameChoiceType extends AbstractType
{
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @param ThemeRepositoryInterface $themeRepository
*/
public function __construct(ThemeRepositoryInterface $themeRepository)
{
$this->themeRepository = $themeRepository;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'choices' => function (Options $options): array {
$themes = $this->themeRepository->findAll();
$choices = [];
foreach ($themes as $theme) {
$choices[$theme->getTitle() ?: $theme->getName()] = $theme->getName();
}
return $choices;
},
]);
}
/**
* {@inheritdoc}
*/
public function getParent(): string
{
return ChoiceType::class;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'sylius_theme_name_choice';
}
}

View file

@ -1,27 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\HierarchyProvider;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class NoopThemeHierarchyProvider implements ThemeHierarchyProviderInterface
{
/**
* {@inheritdoc}
*/
public function getThemeHierarchy(ThemeInterface $theme): array
{
return [$theme];
}
}

View file

@ -1,35 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\HierarchyProvider;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class ThemeHierarchyProvider implements ThemeHierarchyProviderInterface
{
/**
* {@inheritdoc}
*/
public function getThemeHierarchy(ThemeInterface $theme): array
{
$parents = [];
foreach ($theme->getParents() as $parent) {
$parents = array_merge(
$parents,
$this->getThemeHierarchy($parent)
);
}
return array_merge([$theme], $parents);
}
}

View file

@ -1,28 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\HierarchyProvider;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ThemeHierarchyProviderInterface
{
/**
* @param ThemeInterface $theme
*
* @return array|ThemeInterface[]
*
* @throws \InvalidArgumentException If dependencies could not be resolved.
*/
public function getThemeHierarchy(ThemeInterface $theme): array;
}

View file

@ -1,19 +0,0 @@
Copyright (c) 2011-2018 Paweł Jędrzejewski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,38 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class CircularDependencyChecker implements CircularDependencyCheckerInterface
{
/**
* {@inheritdoc}
*/
public function check(ThemeInterface $theme, array $previousThemes = []): void
{
if (0 === count($theme->getParents())) {
return;
}
$previousThemes[] = $theme;
foreach ($theme->getParents() as $parent) {
if (in_array($parent, $previousThemes, true)) {
throw new CircularDependencyFoundException(array_merge($previousThemes, [$parent]));
}
$this->check($parent, $previousThemes);
}
}
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface CircularDependencyCheckerInterface
{
/**
* @param ThemeInterface $theme
*
* @throws CircularDependencyFoundException
*/
public function check(ThemeInterface $theme): void;
}

View file

@ -1,68 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class CircularDependencyFoundException extends \DomainException
{
/**
* @param ThemeInterface[] $themes
* @param \Exception $previous
*/
public function __construct(array $themes, ?\Exception $previous = null)
{
$cycle = $this->getCycleFromArray($themes);
$message = sprintf(
'Circular dependency was found while resolving theme "%s", caused by cycle "%s".',
reset($themes)->getName(),
$this->formatCycleToString($cycle)
);
parent::__construct($message, 0, $previous);
}
/**
* @param array $themes
*
* @return array
*/
private function getCycleFromArray(array $themes): array
{
while (reset($themes) !== end($themes) || 1 === count($themes)) {
array_shift($themes);
}
if (0 === count($themes)) {
throw new \InvalidArgumentException('There is no cycle within given themes.');
}
return $themes;
}
/**
* @param array $themes
*
* @return string
*/
private function formatCycleToString(array $themes): string
{
$themesNames = array_map(function (ThemeInterface $theme) {
return $theme->getName();
}, $themes);
return implode(' -> ', $themesNames);
}
}

View file

@ -1,192 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
use Sylius\Bundle\ThemeBundle\Configuration\ConfigurationProviderInterface;
use Sylius\Bundle\ThemeBundle\Factory\ThemeAuthorFactoryInterface;
use Sylius\Bundle\ThemeBundle\Factory\ThemeFactoryInterface;
use Sylius\Bundle\ThemeBundle\Factory\ThemeScreenshotFactoryInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeAuthor;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeScreenshot;
use Zend\Hydrator\HydrationInterface;
final class ThemeLoader implements ThemeLoaderInterface
{
/**
* @var ConfigurationProviderInterface
*/
private $configurationProvider;
/**
* @var ThemeFactoryInterface
*/
private $themeFactory;
/**
* @var ThemeAuthorFactoryInterface
*/
private $themeAuthorFactory;
/**
* @var ThemeScreenshotFactoryInterface
*/
private $themeScreenshotFactory;
/**
* @var HydrationInterface
*/
private $themeHydrator;
/**
* @var CircularDependencyCheckerInterface
*/
private $circularDependencyChecker;
/**
* @param ConfigurationProviderInterface $configurationProvider
* @param ThemeFactoryInterface $themeFactory
* @param ThemeAuthorFactoryInterface $themeAuthorFactory
* @param ThemeScreenshotFactoryInterface $themeScreenshotFactory
* @param HydrationInterface $themeHydrator
* @param CircularDependencyCheckerInterface $circularDependencyChecker
*/
public function __construct(
ConfigurationProviderInterface $configurationProvider,
ThemeFactoryInterface $themeFactory,
ThemeAuthorFactoryInterface $themeAuthorFactory,
ThemeScreenshotFactoryInterface $themeScreenshotFactory,
HydrationInterface $themeHydrator,
CircularDependencyCheckerInterface $circularDependencyChecker
) {
$this->configurationProvider = $configurationProvider;
$this->themeFactory = $themeFactory;
$this->themeAuthorFactory = $themeAuthorFactory;
$this->themeScreenshotFactory = $themeScreenshotFactory;
$this->themeHydrator = $themeHydrator;
$this->circularDependencyChecker = $circularDependencyChecker;
}
/**
* {@inheritdoc}
*/
public function load(): array
{
$configurations = $this->configurationProvider->getConfigurations();
$themes = $this->initializeThemes($configurations);
$themes = $this->hydrateThemes($configurations, $themes);
$this->checkForCircularDependencies($themes);
return array_values($themes);
}
/**
* @param array $configurations
*
* @return array|ThemeInterface[]
*/
private function initializeThemes(array $configurations): array
{
$themes = [];
foreach ($configurations as $configuration) {
/** @var ThemeInterface $theme */
$themes[$configuration['name']] = $this->themeFactory->create($configuration['name'], $configuration['path']);
}
return $themes;
}
/**
* @param array $configurations
* @param array|ThemeInterface[] $themes
*
* @return array|ThemeInterface[]
*/
private function hydrateThemes(array $configurations, array $themes): array
{
foreach ($configurations as $configuration) {
$themeName = $configuration['name'];
$configuration['parents'] = $this->convertParentsNamesToParentsObjects($themeName, $configuration['parents'], $themes);
$configuration['authors'] = $this->convertAuthorsArraysToAuthorsObjects($configuration['authors']);
$configuration['screenshots'] = $this->convertScreenshotsArraysToScreenshotsObjects($configuration['screenshots']);
$themes[$themeName] = $this->themeHydrator->hydrate($configuration, $themes[$themeName]);
}
return $themes;
}
/**
* @param array|ThemeInterface[] $themes
*/
private function checkForCircularDependencies(array $themes): void
{
try {
foreach ($themes as $theme) {
$this->circularDependencyChecker->check($theme);
}
} catch (CircularDependencyFoundException $exception) {
throw new ThemeLoadingFailedException('Circular dependency found.', 0, $exception);
}
}
/**
* @param string $themeName
* @param array $parentsNames
* @param array $existingThemes
*
* @return array|ThemeInterface[]
*/
private function convertParentsNamesToParentsObjects(string $themeName, array $parentsNames, array $existingThemes): array
{
return array_map(function ($parentName) use ($themeName, $existingThemes) {
if (!isset($existingThemes[$parentName])) {
throw new ThemeLoadingFailedException(sprintf(
'Unexisting theme "%s" is required by "%s".',
$parentName,
$themeName
));
}
return $existingThemes[$parentName];
}, $parentsNames);
}
/**
* @param array $authorsArrays
*
* @return array|ThemeAuthor[]
*/
private function convertAuthorsArraysToAuthorsObjects(array $authorsArrays): array
{
return array_map(function (array $authorArray) {
return $this->themeAuthorFactory->createFromArray($authorArray);
}, $authorsArrays);
}
/**
* @param array $screenshotsArrays
*
* @return array|ThemeScreenshot[]
*/
private function convertScreenshotsArraysToScreenshotsObjects(array $screenshotsArrays): array
{
return array_map(function (array $screenshotArray) {
return $this->themeScreenshotFactory->createFromArray($screenshotArray);
}, $screenshotsArrays);
}
}

View file

@ -1,26 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ThemeLoaderInterface
{
/**
* @return array|ThemeInterface[]
*
* @throws ThemeLoadingFailedException
*/
public function load(): array;
}

View file

@ -1,18 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Loader;
final class ThemeLoadingFailedException extends \DomainException
{
}

View file

@ -1,46 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Component\Filesystem\Filesystem;
final class ApplicationResourceLocator implements ResourceLocatorInterface
{
/**
* @var Filesystem
*/
private $filesystem;
/**
* @param Filesystem $filesystem
*/
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* {@inheritdoc}
*/
public function locateResource(string $resourceName, ThemeInterface $theme): string
{
$path = sprintf('%s/%s', $theme->getPath(), $resourceName);
if (!$this->filesystem->exists($path)) {
throw new ResourceNotFoundException($resourceName, $theme);
}
return $path;
}
}

View file

@ -1,103 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
final class BundleResourceLocator implements ResourceLocatorInterface
{
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var KernelInterface
*/
private $kernel;
/**
* @param Filesystem $filesystem
* @param KernelInterface $kernel
*/
public function __construct(Filesystem $filesystem, KernelInterface $kernel)
{
$this->filesystem = $filesystem;
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*
* @param string $resourcePath Eg. "@AcmeBundle/Resources/views/template.html.twig"
*/
public function locateResource(string $resourcePath, ThemeInterface $theme): string
{
$this->assertResourcePathIsValid($resourcePath);
$bundleName = $this->getBundleNameFromResourcePath($resourcePath);
$resourceName = $this->getResourceNameFromResourcePath($resourcePath);
$bundles = $this->kernel->getBundle($bundleName, false);
foreach ($bundles as $bundle) {
$path = sprintf('%s/%s/%s', $theme->getPath(), $bundle->getName(), $resourceName);
if ($this->filesystem->exists($path)) {
return $path;
}
}
throw new ResourceNotFoundException($resourcePath, $theme);
}
/**
* @param string $resourcePath
*/
private function assertResourcePathIsValid(string $resourcePath): void
{
if (0 !== strpos($resourcePath, '@')) {
throw new \InvalidArgumentException(sprintf('Bundle resource path (given "%s") should start with an "@".', $resourcePath));
}
if (false !== strpos($resourcePath, '..')) {
throw new \InvalidArgumentException(sprintf('File name "%s" contains invalid characters (..).', $resourcePath));
}
if (false === strpos($resourcePath, 'Resources/')) {
throw new \InvalidArgumentException(sprintf('Resource path "%s" should be in bundles\' "Resources/" directory.', $resourcePath));
}
}
/**
* @param string $resourcePath
*
* @return string
*/
private function getBundleNameFromResourcePath(string $resourcePath): string
{
return substr($resourcePath, 1, strpos($resourcePath, '/') - 1);
}
/**
* @param string $resourcePath
*
* @return string
*/
private function getResourceNameFromResourcePath(string $resourcePath): string
{
return substr($resourcePath, strpos($resourcePath, 'Resources/') + strlen('Resources/'));
}
}

View file

@ -1,35 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
interface FileLocatorInterface
{
/**
* @param string $name
*
* @return string
*
* @throws \InvalidArgumentException If name is not valid or file was not found
*/
public function locateFileNamed(string $name): string;
/**
* @param string $name
*
* @return array
*
* @throws \InvalidArgumentException If name is not valid or files were not found
*/
public function locateFilesNamed(string $name): array;
}

View file

@ -1,118 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Factory\FinderFactoryInterface;
use Symfony\Component\Finder\SplFileInfo;
final class RecursiveFileLocator implements FileLocatorInterface
{
/**
* @var FinderFactoryInterface
*/
private $finderFactory;
/**
* @var array
*/
private $paths;
/**
* @var int
*/
private $depth;
/**
* @param FinderFactoryInterface $finderFactory
* @param array|string[] $paths An array of paths where to look for resources
* @param int|null $depth Restrict depth to search for configuration file inside theme folder
*/
public function __construct(FinderFactoryInterface $finderFactory, array $paths, ?int $depth = null)
{
$this->finderFactory = $finderFactory;
$this->paths = $paths;
$this->depth = $depth;
}
/**
* {@inheritdoc}
*/
public function locateFileNamed(string $name): string
{
return $this->doLocateFilesNamed($name)->current();
}
/**
* {@inheritdoc}
*/
public function locateFilesNamed(string $name): array
{
return iterator_to_array($this->doLocateFilesNamed($name));
}
/**
* @param string $name
*
* @return \Generator
*/
private function doLocateFilesNamed(string $name): \Generator
{
$this->assertNameIsNotEmpty($name);
$found = false;
foreach ($this->paths as $path) {
try {
$finder = $this->finderFactory->create();
if ($this->depth !== null) {
$finder->depth(sprintf('<= %d', $this->depth));
}
$finder
->files()
->name($name)
->ignoreUnreadableDirs()
->in($path);
/** @var SplFileInfo $file */
foreach ($finder as $file) {
$found = true;
yield $file->getPathname();
}
} catch (\InvalidArgumentException $exception) {
}
}
if (false === $found) {
throw new \InvalidArgumentException(sprintf(
'The file "%s" does not exist (searched in the following directories: %s).',
$name,
implode(', ', $this->paths)
));
}
}
/**
* @param string $name
*/
private function assertNameIsNotEmpty(string $name): void
{
if (null === $name || '' === $name) {
throw new \InvalidArgumentException(
'An empty file name is not valid to be located.'
);
}
}
}

View file

@ -1,53 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class ResourceLocator implements ResourceLocatorInterface
{
/**
* @var ResourceLocatorInterface
*/
private $applicationResourceLocator;
/**
* @var ResourceLocatorInterface
*/
private $bundleResourceLocator;
/**
* @param ResourceLocatorInterface $applicationResourceLocator
* @param ResourceLocatorInterface $bundleResourceLocator
*/
public function __construct(
ResourceLocatorInterface $applicationResourceLocator,
ResourceLocatorInterface $bundleResourceLocator
) {
$this->applicationResourceLocator = $applicationResourceLocator;
$this->bundleResourceLocator = $bundleResourceLocator;
}
/**
* {@inheritdoc}
*/
public function locateResource(string $resourcePath, ThemeInterface $theme): string
{
if (0 === strpos($resourcePath, '@')) {
return $this->bundleResourceLocator->locateResource($resourcePath, $theme);
}
return $this->applicationResourceLocator->locateResource($resourcePath, $theme);
}
}

View file

@ -1,29 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ResourceLocatorInterface
{
/**
* @param string $resourceName
* @param ThemeInterface $theme
*
* @return string
*
* @throws ResourceNotFoundException
*/
public function locateResource(string $resourceName, ThemeInterface $theme): string;
}

View file

@ -1,32 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Locator;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class ResourceNotFoundException extends \RuntimeException
{
/**
* @param string $resourceName
* @param ThemeInterface $theme
*/
public function __construct(string $resourceName, ThemeInterface $theme)
{
parent::__construct(sprintf(
'Could not find resource "%s" using theme "%s".',
$resourceName,
$theme->getName()
));
}
}

View file

@ -1,213 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Model;
class Theme implements ThemeInterface
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $path;
/**
* @var string|null
*/
protected $title;
/**
* @var string|null
*/
protected $description;
/**
* @var array|ThemeAuthor[]
*/
protected $authors = [];
/**
* @var array|ThemeInterface[]
*/
protected $parents = [];
/**
* @var array|ThemeScreenshot[]
*/
protected $screenshots = [];
/**
* @param string $name
* @param string $path
*/
public function __construct(string $name, string $path)
{
$this->assertNameIsValid($name);
$this->name = $name;
$this->path = $path;
}
/**
* @return string
*/
public function __toString(): string
{
return (string) ($this->title ?: $this->name);
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPath(): string
{
return $this->path;
}
/**
* {@inheritdoc}
*/
public function getTitle(): ?string
{
return $this->title;
}
/**
* {@inheritdoc}
*/
public function setTitle(?string $title): void
{
$this->title = $title;
}
/**
* {@inheritdoc}
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* {@inheritdoc}
*/
public function setDescription(?string $description): void
{
$this->description = $description;
}
/**
* {@inheritdoc}
*/
public function getAuthors(): array
{
return $this->authors;
}
/**
* {@inheritdoc}
*/
public function addAuthor(ThemeAuthor $author): void
{
$this->authors[] = $author;
}
/**
* {@inheritdoc}
*/
public function removeAuthor(ThemeAuthor $author): void
{
$this->authors = array_filter($this->authors, function ($currentAuthor) use ($author) {
return $currentAuthor !== $author;
});
}
/**
* {@inheritdoc}
*/
public function getParents(): array
{
return $this->parents;
}
/**
* {@inheritdoc}
*/
public function addParent(ThemeInterface $theme): void
{
$this->parents[] = $theme;
}
/**
* {@inheritdoc}
*/
public function removeParent(ThemeInterface $theme): void
{
$this->parents = array_filter($this->parents, function ($currentTheme) use ($theme) {
return $currentTheme !== $theme;
});
}
/**
* {@inheritdoc}
*/
public function getScreenshots(): array
{
return $this->screenshots;
}
/**
* {@inheritdoc}
*/
public function addScreenshot(ThemeScreenshot $screenshot): void
{
$this->screenshots[] = $screenshot;
}
/**
* {@inheritdoc}
*/
public function removeScreenshot(ThemeScreenshot $screenshot): void
{
$this->screenshots = array_filter($this->screenshots, function ($currentScreenshot) use ($screenshot) {
return $currentScreenshot !== $screenshot;
});
}
/**
* @param string $name
*/
private function assertNameIsValid(string $name): void
{
$pattern = '/^[a-zA-Z0-9\-]+\/[a-zA-Z0-9\-]+$/';
if (false === (bool) preg_match($pattern, $name)) {
throw new \InvalidArgumentException(sprintf(
'Given name "%s" does not match regular expression "%s".',
$name,
$pattern
));
}
}
}

View file

@ -1,77 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Model;
final class ThemeAuthor
{
/**
* @var string|null
*/
private $name;
/**
* @var string|null
*/
private $email;
/**
* @var string|null
*/
private $homepage;
/**
* @var string|null
*/
private $role;
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): void
{
$this->email = $email;
}
public function getHomepage(): ?string
{
return $this->homepage;
}
public function setHomepage(?string $homepage): void
{
$this->homepage = $homepage;
}
public function getRole(): ?string
{
return $this->role;
}
public function setRole(?string $role): void
{
$this->role = $role;
}
}

View file

@ -1,92 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Model;
interface ThemeInterface
{
/**
* @return string
*/
public function getName(): string;
/**
* @return string
*/
public function getPath(): string;
/**
* @return string|null
*/
public function getTitle(): ?string;
/**
* @param string|null $title
*/
public function setTitle(?string $title): void;
/**
* @return string|null
*/
public function getDescription(): ?string;
/**
* @param string|null $description
*/
public function setDescription(?string $description): void;
/**
* @return array|ThemeAuthor[]
*/
public function getAuthors(): array;
/**
* @param ThemeAuthor $author
*/
public function addAuthor(ThemeAuthor $author): void;
/**
* @param ThemeAuthor $author
*/
public function removeAuthor(ThemeAuthor $author): void;
/**
* @return array|ThemeInterface[]
*/
public function getParents(): array;
/**
* @param ThemeInterface $theme
*/
public function addParent(self $theme): void;
/**
* @param ThemeInterface $theme
*/
public function removeParent(self $theme): void;
/**
* @return array|ThemeScreenshot[]
*/
public function getScreenshots(): array;
/**
* @param ThemeScreenshot $screenshot
*/
public function addScreenshot(ThemeScreenshot $screenshot): void;
/**
* @param ThemeScreenshot $screenshot
*/
public function removeScreenshot(ThemeScreenshot $screenshot): void;
}

View file

@ -1,80 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Model;
final class ThemeScreenshot
{
/**
* @var string
*/
private $path;
/**
* @var string|null
*/
private $title;
/**
* @var string|null
*/
private $description;
/**
* @param string $path
*/
public function __construct(string $path)
{
$this->path = $path;
}
/**
* @return string
*/
public function getPath(): string
{
return $this->path;
}
/**
* @return string|null
*/
public function getTitle(): ?string
{
return $this->title;
}
/**
* @param string|null $title
*/
public function setTitle(?string $title): void
{
$this->title = $title;
}
/**
* @return string|null
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string|null $description
*/
public function setDescription(?string $description): void
{
$this->description = $description;
}
}

View file

@ -1,47 +0,0 @@
SyliusThemeBundle [![Build status...](https://secure.travis-ci.org/Sylius/SyliusThemeBundle.png?branch=master)](http://travis-ci.org/Sylius/SyliusThemeBundle)
==================
Theme management for [**Symfony2**](http://symfony.com).
Sylius
------
![Sylius](https://demo.sylius.com/assets/shop/img/logo.png)
Sylius is an Open Source eCommerce solution built from decoupled components with powerful API and the highest quality code. [Read more on sylius.com](http://sylius.com).
Documentation
-------------
Documentation is available on [**docs.sylius.com**](http://docs.sylius.com/en/latest/components_and_bundles/bundles/SyliusThemeBundle/index.html).
Contributing
------------
[This page](http://docs.sylius.com/en/latest/contributing/index.html) contains all the information about contributing to Sylius.
Follow Sylius' Development
--------------------------
If you want to keep up with the updates and latest features, follow us on the following channels:
* [Official Blog](https://sylius.com/blog)
* [Sylius on Twitter](https://twitter.com/Sylius)
* [Sylius on Facebook](https://facebook.com/SyliusEcommerce)
Bug tracking
------------
Sylius uses [GitHub issues](https://github.com/Sylius/Sylius/issues).
If you have found bug, please create an issue.
MIT License
-----------
License can be found [here](https://github.com/Sylius/Sylius/blob/master/LICENSE).
Authors
-------
The bundle was originally created by [Kamil Kokot](http://kamil.kokot.me).
See the list of [contributors](https://github.com/Sylius/SyliusThemeBundle/contributors).

View file

@ -1,93 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Repository;
use Sylius\Bundle\ThemeBundle\Loader\ThemeLoaderInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
final class InMemoryThemeRepository implements ThemeRepositoryInterface
{
/**
* @var ThemeInterface[]
*/
private $themes = [];
/**
* @var ThemeLoaderInterface
*/
private $themeLoader;
/**
* @var bool
*/
private $themesLoaded = false;
/**
* @param ThemeLoaderInterface $themeLoader
*/
public function __construct(ThemeLoaderInterface $themeLoader)
{
$this->themeLoader = $themeLoader;
}
/**
* {@inheritdoc}
*/
public function findAll(): array
{
$this->loadThemesIfNeeded();
return $this->themes;
}
/**
* {@inheritdoc}
*/
public function findOneByName(string $name): ?ThemeInterface
{
$this->loadThemesIfNeeded();
return $this->themes[$name] ?? null;
}
/**
* {@inheritdoc}
*/
public function findOneByTitle(string $title): ?ThemeInterface
{
$this->loadThemesIfNeeded();
foreach ($this->themes as $theme) {
if ($theme->getTitle() === $title) {
return $theme;
}
}
return null;
}
private function loadThemesIfNeeded(): void
{
if ($this->themesLoaded) {
return;
}
$themes = $this->themeLoader->load();
foreach ($themes as $theme) {
$this->themes[$theme->getName()] = $theme;
}
$this->themesLoaded = true;
}
}

View file

@ -1,38 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Repository;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
interface ThemeRepositoryInterface
{
/**
* @return array|ThemeInterface[]
*/
public function findAll(): array;
/**
* @param string $name
*
* @return ThemeInterface|null
*/
public function findOneByName(string $name): ?ThemeInterface;
/**
* @param string $title
*
* @return ThemeInterface|null
*/
public function findOneByTitle(string $title): ?ThemeInterface;
}

View file

@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.theme.context.settable" class="Sylius\Bundle\ThemeBundle\Context\SettableThemeContext" public="false">
<argument type="service" id="sylius.theme.hierarchy_provider" />
</service>
<service id="sylius.factory.theme" class="Sylius\Bundle\ThemeBundle\Factory\ThemeFactory" />
<service id="sylius.factory.theme_author" class="Sylius\Bundle\ThemeBundle\Factory\ThemeAuthorFactory" public="false" />
<service id="sylius.factory.theme_screenshot" class="Sylius\Bundle\ThemeBundle\Factory\ThemeScreenshotFactory" public="false" />
<service id="sylius.repository.theme" class="Sylius\Bundle\ThemeBundle\Repository\InMemoryThemeRepository">
<argument type="service" id="sylius.theme.loader" />
</service>
<service id="sylius.theme.hydrator" class="Zend\Hydrator\Reflection" public="false" />
<service id="sylius.theme.circular_dependency_checker" class="Sylius\Bundle\ThemeBundle\Loader\CircularDependencyChecker" public="false" />
<service id="sylius.theme.loader" class="Sylius\Bundle\ThemeBundle\Loader\ThemeLoader" public="false">
<argument type="service" id="sylius.theme.configuration.provider" />
<argument type="service" id="sylius.factory.theme" />
<argument type="service" id="sylius.factory.theme_author" />
<argument type="service" id="sylius.factory.theme_screenshot" />
<argument type="service" id="sylius.theme.hydrator" />
<argument type="service" id="sylius.theme.circular_dependency_checker" />
</service>
<service id="sylius.collector.theme" class="Sylius\Bundle\ThemeBundle\Collector\ThemeCollector" public="false">
<argument type="service" id="sylius.repository.theme" />
<argument type="service" id="sylius.context.theme" />
<argument type="service" id="sylius.theme.hierarchy_provider" />
<tag name="data_collector" template="SyliusThemeBundle:Collector:theme" id="sylius_theme" />
</service>
<service id="sylius.theme.hierarchy_provider" class="Sylius\Bundle\ThemeBundle\HierarchyProvider\ThemeHierarchyProvider" public="false" />
<service id="sylius.theme.filesystem" class="Sylius\Bundle\ThemeBundle\Filesystem\Filesystem" public="false" />
<service id="sylius.theme.finder_factory" class="Sylius\Bundle\ThemeBundle\Factory\FinderFactory" public="false" />
<service id="sylius.theme.form.type.theme_choice" class="Sylius\Bundle\ThemeBundle\Form\Type\ThemeChoiceType">
<argument type="service" id="sylius.repository.theme" />
<tag name="form.type" />
</service>
<service id="sylius.theme.form.type.theme_name_choice" class="Sylius\Bundle\ThemeBundle\Form\Type\ThemeNameChoiceType">
<argument type="service" id="sylius.repository.theme" />
<tag name="form.type" />
</service>
<service id="sylius.theme.configuration" class="Sylius\Bundle\ThemeBundle\Configuration\ThemeConfiguration" public="false" />
<service id="sylius.theme.configuration.processor" class="Sylius\Bundle\ThemeBundle\Configuration\SymfonyConfigurationProcessor" public="false">
<argument type="service" id="sylius.theme.configuration" />
<argument type="service">
<service class="Symfony\Component\Config\Definition\Processor" />
</argument>
</service>
<service id="sylius.theme.configuration.provider" class="Sylius\Bundle\ThemeBundle\Configuration\CompositeConfigurationProvider">
<argument type="collection" /> <!-- an array of configuration providers -->
</service>
</services>
</container>

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.theme.asset.assets_installer" class="Sylius\Bundle\ThemeBundle\Asset\Installer\AssetsInstaller">
<argument type="service" id="filesystem" />
<argument type="service" id="kernel" />
<argument type="service" id="sylius.repository.theme" />
<argument type="service" id="sylius.theme.hierarchy_provider" />
<argument type="service" id="sylius.theme.asset.path_resolver" />
</service>
<service id="sylius.theme.asset.assets_installer.output_aware" class="Sylius\Bundle\ThemeBundle\Asset\Installer\OutputAwareAssetsInstaller" decorates="sylius.theme.asset.assets_installer" decoration-priority="256">
<argument type="service" id="sylius.theme.asset.assets_installer.output_aware.inner" />
</service>
<service id="sylius.theme.asset.path_resolver" class="Sylius\Bundle\ThemeBundle\Asset\PathResolver" public="false" />
<!-- Overridden services -->
<service id="assets.path_package" class="Sylius\Bundle\ThemeBundle\Asset\Package\PathPackage" abstract="true">
<argument /> <!-- base path -->
<argument /> <!-- version strategy -->
<argument type="service" id="sylius.context.theme" />
<argument type="service" id="sylius.theme.asset.path_resolver" />
<argument type="service" id="assets.context" />
</service>
<service id="assets.url_package" class="Sylius\Bundle\ThemeBundle\Asset\Package\UrlPackage" abstract="true">
<argument /> <!-- base URLs -->
<argument /> <!-- version strategy -->
<argument type="service" id="sylius.context.theme" />
<argument type="service" id="sylius.theme.asset.path_resolver" />
<argument type="service" id="assets.context" />
</service>
</services>
</container>

View file

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.theme.locator.resource" class="Sylius\Bundle\ThemeBundle\Locator\ResourceLocator" public="false">
<argument type="service" id="sylius.theme.locator.application_resource" />
<argument type="service" id="sylius.theme.locator.bundle_resource" />
</service>
<service id="sylius.theme.locator.application_resource" class="Sylius\Bundle\ThemeBundle\Locator\ApplicationResourceLocator">
<argument type="service" id="filesystem" />
</service>
<service id="sylius.theme.locator.bundle_resource" class="Sylius\Bundle\ThemeBundle\Locator\BundleResourceLocator">
<argument type="service" id="filesystem" />
<argument type="service" id="kernel" />
</service>
<service id="sylius.theme.templating.name_parser" class="Sylius\Bundle\ThemeBundle\Templating\TemplateNameParser" decorates="templating.name_parser" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.templating.name_parser.inner" />
<argument type="service" id="kernel" />
</service>
<service id="sylius.theme.templating.cache" class="Doctrine\Common\Cache\ArrayCache" />
<service id="sylius.theme.templating.locator" class="Sylius\Bundle\ThemeBundle\Templating\Locator\TemplateLocator" public="false">
<argument type="service" id="sylius.theme.locator.resource" />
</service>
<service id="sylius.theme.templating.locator.cached" class="Sylius\Bundle\ThemeBundle\Templating\Locator\CachedTemplateLocator" decorates="sylius.theme.templating.locator" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.templating.locator.cached.inner" />
<argument type="service" id="sylius.theme.templating.cache" />
</service>
<service id="sylius.theme.templating.file_locator" class="Sylius\Bundle\ThemeBundle\Templating\Locator\TemplateFileLocator" decorates="templating.locator" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.templating.file_locator.inner" />
<argument type="service" id="sylius.context.theme" />
<argument type="service" id="sylius.theme.hierarchy_provider" />
<argument type="service" id="sylius.theme.templating.locator" />
<argument>%kernel.cache_dir%</argument>
</service>
<service id="sylius.theme.templating.cache.clearer" class="Sylius\Bundle\ThemeBundle\Templating\Cache\Clearer\TemplatePathsCacheClearer" public="false">
<argument type="service" id="sylius.theme.templating.cache" />
<tag name="kernel.cache_clearer" priority="20" />
</service>
<service id="sylius.theme.templating.cache.warmer" class="Sylius\Bundle\ThemeBundle\Templating\Cache\Warmer\TemplatePathsCacheWarmer" public="false">
<argument type="service" id="templating.finder" />
<argument type="service" id="sylius.theme.templating.locator" />
<argument type="service" id="sylius.repository.theme" />
<argument type="service" id="sylius.theme.templating.cache" />
<tag name="kernel.cache_warmer" priority="20" />
</service>
<!-- Overridden services -->
<service id="templating.cache_warmer.template_paths" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplatePathsCacheWarmer" public="false">
<argument type="service" id="templating.finder" />
<argument type="service" id="sylius.theme.templating.file_locator.inner" /> <!-- using default templating locator, as TemplatePathsCacheWarmer accepts TemplateLocator class instances only -->
<tag name="kernel.cache_warmer" priority="20" />
</service>
</services>
</container>

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.theme.translation.translator" class="Sylius\Bundle\ThemeBundle\Translation\Translator" decorates="translator.default" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.translation.loader_provider" />
<argument type="service" id="sylius.theme.translation.resource_provider" />
<argument type="service" id="translator.selector" />
<argument>%kernel.default_locale%</argument>
<argument type="collection">
<argument key="cache_dir">%kernel.cache_dir%/translations</argument>
<argument key="debug">%kernel.debug%</argument>
</argument>
</service>
<service id="sylius.theme.translation.theme_aware_translator" class="Sylius\Bundle\ThemeBundle\Translation\ThemeAwareTranslator" decorates="sylius.theme.translation.translator" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.translation.theme_aware_translator.inner" />
<argument type="service" id="sylius.context.theme" />
</service>
<service id="sylius.theme.translation.loader_provider" class="Sylius\Bundle\ThemeBundle\Translation\Provider\Loader\TranslatorLoaderProvider" public="false">
<argument type="collection" /> <!-- loaders -->
</service>
<service id="sylius.theme.translation.resource_provider" class="Sylius\Bundle\ThemeBundle\Translation\Provider\Resource\CompositeTranslatorResourceProvider" public="false">
<argument type="collection">
<argument type="service" id="sylius.theme.translation.resource_provider.default" />
<argument type="service" id="sylius.theme.translation.resource_provider.theme_aware" />
</argument>
</service>
<service id="sylius.theme.translation.resource_provider.default" class="Sylius\Bundle\ThemeBundle\Translation\Provider\Resource\TranslatorResourceProvider" public="false">
<argument type="collection" /> <!-- resources filepaths -->
</service>
<service id="sylius.theme.translation.resource_provider.theme_aware" class="Sylius\Bundle\ThemeBundle\Translation\Provider\Resource\ThemeTranslatorResourceProvider" public="false">
<argument type="service" id="sylius.theme.translation.files_finder" />
<argument type="service" id="sylius.repository.theme" />
<argument type="service" id="sylius.theme.hierarchy_provider" />
</service>
<service id="sylius.theme.translation.files_finder" class="Sylius\Bundle\ThemeBundle\Translation\Finder\TranslationFilesFinder" public="false">
<argument type="service" id="sylius.theme.finder_factory" />
</service>
<service id="sylius.theme.translation.ordering_files_finder" class="Sylius\Bundle\ThemeBundle\Translation\Finder\OrderingTranslationFilesFinder" decorates="sylius.theme.translation.files_finder" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.translation.ordering_files_finder.inner" />
</service>
</services>
</container>

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.theme.twig.loader" class="Sylius\Bundle\ThemeBundle\Twig\ThemeFilesystemLoader" decorates="twig.loader" decoration-priority="256" public="false">
<argument type="service" id="sylius.theme.twig.loader.inner" />
<argument type="service" id="templating.locator" />
<argument type="service" id="templating.name_parser" />
</service>
</services>
</container>

View file

@ -1,3 +0,0 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 1792 1792" enable-background="new 0 0 24 24" xml:space="preserve">>
<path fill="#AAAAAA" d="M1664 960q-152-236-381-353 61 104 61 225 0 185-131.5 316.5t-316.5 131.5-316.5-131.5-131.5-316.5q0-121 61-225-229 117-381 353 133 205 333.5 326.5t434.5 121.5 434.5-121.5 333.5-326.5zm-720-384q0-20-14-34t-34-14q-125 0-214.5 89.5t-89.5 214.5q0 20 14 34t34 14 34-14 14-34q0-86 61-147t147-61q20 0 34-14t14-34zm848 384q0 34-20 69-140 230-376.5 368.5t-499.5 138.5-499.5-139-376.5-368q-20-35-20-69t20-69q140-229 376.5-368t499.5-139 499.5 139 376.5 368q20 35 20 69z" />
</svg>

Before

Width:  |  Height:  |  Size: 670 B

View file

@ -1,113 +0,0 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% import _self as helper %}
{% block toolbar %}
{% if collector.themes is not empty %}
{% set icon %}
{{ include('@SyliusTheme/Collector/Icon/theme.svg') }}
<span class="sf-toolbar-value">{{ collector.usedTheme|default(collector.themes|length) }}</span>
{% endset %}
{% set text %}
<div class="sf-toolbar-info-piece">
<b>All themes</b>
<span class="sf-toolbar-status">{{ collector.themes|length }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Used themes</b>
<span class="sf-toolbar-status">{{ collector.usedThemes|length }}</span>
</div>
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig') }}
{% endif %}
{% endblock %}
{% block menu %}
<span class="label {% if collector.usedThemes is empty %}disabled{% endif %}">
<span class="icon">{{ include('@SyliusTheme/Collector/Icon/theme.svg') }}</span>
<strong>Themes</strong>
<span class="count">
<span>{{ collector.usedThemes|length }}</span>
</span>
</span>
{% endblock %}
{% block panel %}
<h2>Theme Metrics</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.usedThemes|length }}</span>
<span class="label">Used themes</span>
</div>
<div class="metric">
<span class="value">{{ collector.themes|length }}</span>
<span class="label">All themes</span>
</div>
</div>
<h2>Themes List</h2>
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Used <span class="badge">{{ collector.usedThemes|length }}</span></h3>
<div class="tab-content">
<p class="help">
These are themes used.
</p>
{% if collector.usedThemes is empty %}
<div class="empty">
<p>No themes were used.</p>
</div>
{% else %}
{{ helper.render_table(collector.usedThemes) }}
{% endif %}
</div>
</div>
<div class="tab">
<h3 class="tab-title">All <span class="badge">{{ collector.themes|length }}</span></h3>
<div class="tab-content">
<p class="help">
These are themes found.
</p>
{% if collector.themes is empty %}
<div class="empty">
<p>No themes were found.</p>
</div>
{% else %}
{{ helper.render_table(collector.themes) }}
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% macro render_table(themes) %}
<table>
<thead>
<tr>
<th>Name</th>
<th>Path</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for theme in themes %}
<tr>
<td class="font-normal text-small text-bold">{{ theme.name }}</td>
<td class="font-normal text-small">{{ theme.path }}</td>
<td class="font-normal text-small">{{ theme.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}

View file

@ -1,41 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle;
use Sylius\Bundle\ThemeBundle\Configuration\Filesystem\FilesystemConfigurationSourceFactory;
use Sylius\Bundle\ThemeBundle\Configuration\Test\TestConfigurationSourceFactory;
use Sylius\Bundle\ThemeBundle\DependencyInjection\SyliusThemeExtension;
use Sylius\Bundle\ThemeBundle\Translation\DependencyInjection\Compiler\TranslatorFallbackLocalesPass;
use Sylius\Bundle\ThemeBundle\Translation\DependencyInjection\Compiler\TranslatorLoaderProviderPass;
use Sylius\Bundle\ThemeBundle\Translation\DependencyInjection\Compiler\TranslatorResourceProviderPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
final class SyliusThemeBundle extends Bundle
{
/**
* {@inheritdoc}
*/
public function build(ContainerBuilder $container): void
{
/** @var SyliusThemeExtension $themeExtension */
$themeExtension = $container->getExtension('sylius_theme');
$themeExtension->addConfigurationSourceFactory(new FilesystemConfigurationSourceFactory());
$themeExtension->addConfigurationSourceFactory(new TestConfigurationSourceFactory());
$container->addCompilerPass(new TranslatorFallbackLocalesPass());
$container->addCompilerPass(new TranslatorLoaderProviderPass());
$container->addCompilerPass(new TranslatorResourceProviderPass());
}
}

View file

@ -1,46 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Cache\Clearer;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\ClearableCache;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
final class TemplatePathsCacheClearer implements CacheClearerInterface
{
/**
* @var Cache
*/
private $cache;
/**
* @param Cache $cache
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function clear($cacheDir): void
{
if (!$this->cache instanceof ClearableCache) {
return;
}
$this->cache->deleteAll();
}
}

View file

@ -1,122 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Cache\Warmer;
use Doctrine\Common\Cache\Cache;
use Sylius\Bundle\ThemeBundle\Locator\ResourceNotFoundException;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
use Sylius\Bundle\ThemeBundle\Templating\Locator\TemplateLocatorInterface;
use Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinderInterface;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
final class TemplatePathsCacheWarmer implements CacheWarmerInterface
{
/**
* @var TemplateFinderInterface
*/
private $templateFinder;
/**
* @var TemplateLocatorInterface
*/
private $templateLocator;
/**
* @var ThemeRepositoryInterface
*/
private $themeRepository;
/**
* @var Cache
*/
private $cache;
/**
* @param TemplateFinderInterface $templateFinder
* @param TemplateLocatorInterface $templateLocator
* @param ThemeRepositoryInterface $themeRepository
* @param Cache $cache
*/
public function __construct(
TemplateFinderInterface $templateFinder,
TemplateLocatorInterface $templateLocator,
ThemeRepositoryInterface $themeRepository,
Cache $cache
) {
$this->templateFinder = $templateFinder;
$this->templateLocator = $templateLocator;
$this->themeRepository = $themeRepository;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function warmUp($cacheDir): void
{
$templates = $this->templateFinder->findAllTemplates();
/** @var TemplateReferenceInterface $template */
foreach ($templates as $template) {
$this->warmUpTemplate($template);
}
}
/**
* {@inheritdoc}
*/
public function isOptional(): bool
{
return true;
}
/**
* @param TemplateReferenceInterface $template
*/
private function warmUpTemplate(TemplateReferenceInterface $template): void
{
/** @var ThemeInterface $theme */
foreach ($this->themeRepository->findAll() as $theme) {
$this->warmUpThemeTemplate($template, $theme);
}
}
/**
* @param TemplateReferenceInterface $template
* @param ThemeInterface $theme
*/
private function warmUpThemeTemplate(TemplateReferenceInterface $template, ThemeInterface $theme): void
{
try {
$location = $this->templateLocator->locateTemplate($template, $theme);
} catch (ResourceNotFoundException $exception) {
$location = null;
}
$this->cache->save($this->getCacheKey($template, $theme), $location);
}
/**
* @param TemplateReferenceInterface $template
* @param ThemeInterface $theme
*
* @return string
*/
private function getCacheKey(TemplateReferenceInterface $template, ThemeInterface $theme): string
{
return $template->getLogicalName() . '|' . $theme->getName();
}
}

View file

@ -1,72 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Locator;
use Doctrine\Common\Cache\Cache;
use Sylius\Bundle\ThemeBundle\Locator\ResourceNotFoundException;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
final class CachedTemplateLocator implements TemplateLocatorInterface
{
/**
* @var TemplateLocatorInterface
*/
private $decoratedTemplateLocator;
/**
* @var Cache
*/
private $cache;
/**
* @param TemplateLocatorInterface $decoratedTemplateLocator
* @param Cache $cache
*/
public function __construct(TemplateLocatorInterface $decoratedTemplateLocator, Cache $cache)
{
$this->decoratedTemplateLocator = $decoratedTemplateLocator;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function locateTemplate(TemplateReferenceInterface $template, ThemeInterface $theme): string
{
$cacheKey = $this->getCacheKey($template, $theme);
if ($this->cache->contains($cacheKey)) {
$location = $this->cache->fetch($cacheKey);
if (null === $location) {
throw new ResourceNotFoundException($template->getPath(), $theme);
}
return $location;
}
return $this->decoratedTemplateLocator->locateTemplate($template, $theme);
}
/**
* @param TemplateReferenceInterface $template
* @param ThemeInterface $theme
*
* @return string
*/
private function getCacheKey(TemplateReferenceInterface $template, ThemeInterface $theme): string
{
return $template->getLogicalName() . '|' . $theme->getName();
}
}

View file

@ -1,107 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Locator;
use Sylius\Bundle\ThemeBundle\Context\EmptyThemeContext;
use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
use Sylius\Bundle\ThemeBundle\HierarchyProvider\NoopThemeHierarchyProvider;
use Sylius\Bundle\ThemeBundle\HierarchyProvider\ThemeHierarchyProviderInterface;
use Sylius\Bundle\ThemeBundle\Locator\ResourceNotFoundException;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
/**
* {@inheritdoc}
*/
final class TemplateFileLocator implements FileLocatorInterface, \Serializable
{
/**
* @var FileLocatorInterface
*/
private $decoratedFileLocator;
/**
* @var ThemeContextInterface
*/
private $themeContext;
/**
* @var ThemeHierarchyProviderInterface
*/
private $themeHierarchyProvider;
/**
* @var TemplateLocatorInterface
*/
private $templateLocator;
/**
* @param FileLocatorInterface $decoratedFileLocator
* @param ThemeContextInterface $themeContext
* @param ThemeHierarchyProviderInterface $themeHierarchyProvider
* @param TemplateLocatorInterface $templateLocator
*/
public function __construct(
FileLocatorInterface $decoratedFileLocator,
ThemeContextInterface $themeContext,
ThemeHierarchyProviderInterface $themeHierarchyProvider,
TemplateLocatorInterface $templateLocator
) {
$this->decoratedFileLocator = $decoratedFileLocator;
$this->themeContext = $themeContext;
$this->themeHierarchyProvider = $themeHierarchyProvider;
$this->templateLocator = $templateLocator;
}
/**
* {@inheritdoc}
*/
public function locate($template, $currentPath = null, $first = true): string
{
if (!$template instanceof TemplateReferenceInterface) {
throw new \InvalidArgumentException('The template must be an instance of TemplateReferenceInterface.');
}
$theme = $this->themeContext->getTheme();
$themes = $theme !== null ? $this->themeHierarchyProvider->getThemeHierarchy($theme) : [];
foreach ($themes as $theme) {
try {
return $this->templateLocator->locateTemplate($template, $theme);
} catch (ResourceNotFoundException $exception) {
// Ignore if resource cannot be found in given theme.
}
}
return $this->decoratedFileLocator->locate($template, $currentPath, $first);
}
/**
* {@inheritdoc}
*/
public function serialize(): string
{
return serialize($this->decoratedFileLocator);
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized): void
{
$this->decoratedFileLocator = unserialize($serialized);
$this->themeContext = new EmptyThemeContext();
$this->themeHierarchyProvider = new NoopThemeHierarchyProvider();
}
}

View file

@ -1,42 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Locator;
use Sylius\Bundle\ThemeBundle\Locator\ResourceLocatorInterface;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
final class TemplateLocator implements TemplateLocatorInterface
{
/**
* @var ResourceLocatorInterface
*/
private $resourceLocator;
/**
* @param ResourceLocatorInterface $resourceLocator
*/
public function __construct(ResourceLocatorInterface $resourceLocator)
{
$this->resourceLocator = $resourceLocator;
}
/**
* {@inheritdoc}
*/
public function locateTemplate(TemplateReferenceInterface $template, ThemeInterface $theme): string
{
return $this->resourceLocator->locateResource($template->getPath(), $theme);
}
}

View file

@ -1,31 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating\Locator;
use Sylius\Bundle\ThemeBundle\Locator\ResourceNotFoundException;
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
interface TemplateLocatorInterface
{
/**
* @param TemplateReferenceInterface $template
* @param ThemeInterface $theme
*
* @return string
*
* @throws ResourceNotFoundException
*/
public function locateTemplate(TemplateReferenceInterface $template, ThemeInterface $theme): string;
}

View file

@ -1,87 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Templating;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Templating\TemplateNameParserInterface;
use Symfony\Component\Templating\TemplateReferenceInterface;
/**
* TemplateNameParser converts template names from the short notation
* "@Bundle/Section/template.format.engine" to TemplateReferenceInterface instances.
*/
final class TemplateNameParser implements TemplateNameParserInterface
{
/**
* @var TemplateNameParserInterface
*/
private $decoratedParser;
/**
* @var KernelInterface
*/
private $kernel;
/**
* @var array|TemplateReferenceInterface[]
*/
private $cache = [];
/**
* @param TemplateNameParserInterface $decoratedParser
* @param KernelInterface $kernel
*/
public function __construct(TemplateNameParserInterface $decoratedParser, KernelInterface $kernel)
{
$this->decoratedParser = $decoratedParser;
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public function parse($name): TemplateReferenceInterface
{
if ($name instanceof TemplateReferenceInterface) {
return $name;
}
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
if (!preg_match('/^(?:@([^\/]*)|)(?:\/(.+))?\/(.+)\.([^\.]+)\.([^\.]+)$/', $name, $matches)) {
return $this->decoratedParser->parse($name);
}
$template = new TemplateReference(
$matches[1] ? $matches[1] . 'Bundle' : '',
$matches[2],
$matches[3],
$matches[4],
$matches[5]
);
if ($template->get('bundle')) {
try {
$this->kernel->getBundle($template->get('bundle'));
} catch (\Exception $e) {
return $this->decoratedParser->parse($name);
}
}
return $this->cache[$name] = $template;
}
}

View file

@ -1,392 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Tests\Configuration;
use Matthias\SymfonyConfigTest\PhpUnit\ConfigurationTestCaseTrait;
use PHPUnit\Framework\TestCase;
use Sylius\Bundle\ThemeBundle\Configuration\ThemeConfiguration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class ThemeConfigurationTest extends TestCase
{
use ConfigurationTestCaseTrait;
/**
* @test
*/
public function it_requires_only_name(): void
{
$this->assertProcessedConfigurationEquals(
[
['name' => 'example/sylius-theme'],
],
['name' => 'example/sylius-theme'],
'name'
);
}
/**
* @test
*/
public function its_name_is_required_and_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
[/* no name defined */],
],
'name'
);
$this->assertPartialConfigurationIsInvalid(
[
['name' => ''],
],
'name'
);
}
/**
* @test
*/
public function its_title_is_optional_but_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['title' => ''],
],
'title'
);
$this->assertConfigurationIsValid(
[
['title' => 'Lorem ipsum'],
],
'title'
);
}
/**
* @test
*/
public function its_description_is_optional_but_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['description' => ''],
],
'description'
);
$this->assertConfigurationIsValid(
[
['description' => 'Lorem ipsum dolor sit amet'],
],
'description'
);
}
/**
* @test
*/
public function its_path_is_optional_but_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['path' => ''],
],
'path'
);
$this->assertConfigurationIsValid(
[
['path' => '/theme/path'],
],
'path'
);
}
/**
* @test
*/
public function its_authors_are_optional(): void
{
$this->assertConfigurationIsValid(
[
[/* no authors defined */],
],
'authors'
);
}
/**
* @test
*/
public function its_author_can_have_only_name_email_homepage_and_role_properties(): void
{
$this->assertConfigurationIsValid(
[
['authors' => [['name' => 'Kamil Kokot']]],
],
'authors'
);
$this->assertConfigurationIsValid(
[
['authors' => [['email' => 'kamil@kokot.me']]],
],
'authors'
);
$this->assertConfigurationIsValid(
[
['authors' => [['homepage' => 'http://kamil.kokot.me']]],
],
'authors'
);
$this->assertConfigurationIsValid(
[
['authors' => [['role' => 'Developer']]],
],
'authors'
);
$this->assertPartialConfigurationIsInvalid(
[
['authors' => [['undefined' => '42']]],
],
'authors'
);
}
/**
* @test
*/
public function its_author_must_have_at_least_one_property(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['authors' => [[/* empty author */]]],
],
'authors',
'Author cannot be empty'
);
}
/**
* @test
*/
public function its_authors_replaces_other_authors_defined_elsewhere(): void
{
$this->assertProcessedConfigurationEquals(
[
['authors' => [['name' => 'Kamil Kokot']]],
['authors' => [['name' => 'Krzysztof Krawczyk']]],
],
['authors' => [['name' => 'Krzysztof Krawczyk']]],
'authors'
);
}
/**
* @test
*/
public function it_ignores_undefined_root_level_fields(): void
{
$this->assertConfigurationIsValid(
[
['name' => 'example/sylius-theme', 'undefined_variable' => '42'],
]
);
}
/**
* @test
*/
public function its_parents_are_optional_but_has_to_have_at_least_one_element(): void
{
$this->assertConfigurationIsValid(
[
[],
],
'parents'
);
$this->assertPartialConfigurationIsInvalid(
[
['parents' => [/* no elements */]],
],
'parents'
);
}
/**
* @test
*/
public function its_parent_is_strings(): void
{
$this->assertConfigurationIsValid(
[
['parents' => ['example/parent-theme', 'example/parent-theme-2']],
],
'parents'
);
}
/**
* @test
*/
public function its_parent_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['parents' => ['']],
],
'parents'
);
}
/**
* @test
*/
public function its_parents_replaces_other_parents_defined_elsewhere(): void
{
$this->assertProcessedConfigurationEquals(
[
['parents' => ['example/first-theme']],
['parents' => ['example/second-theme']],
],
['parents' => ['example/second-theme']],
'parents'
);
}
/**
* @test
*/
public function its_screenshots_are_strings(): void
{
$this->assertConfigurationIsValid(
[
['screenshots' => ['screenshot/krzysztof-krawczyk.jpg', 'screenshot/ryszard-rynkowski.jpg']],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_are_optional(): void
{
$this->assertConfigurationIsValid(
[
[/* no screenshots defined */],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_must_have_at_least_one_element(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['screenshots' => [/* no elements */]],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['screenshots' => ['']],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_replaces_other_screenshots_defined_elsewhere(): void
{
$this->assertProcessedConfigurationEquals(
[
['screenshots' => ['screenshot/zbigniew-holdys.jpg']],
['screenshots' => ['screenshot/maryla-rodowicz.jpg']],
],
['screenshots' => [['path' => 'screenshot/maryla-rodowicz.jpg']]],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_are_an_array(): void
{
$this->assertConfigurationIsValid(
[
['screenshots' => [['path' => 'screenshot/rick-astley.jpg']]],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_must_have_a_path(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['screenshots' => [['title' => 'Candy shop']]],
],
'screenshots'
);
}
/**
* @test
*/
public function its_screenshots_have_optional_title_and_description(): void
{
$this->assertConfigurationIsValid(
[
['screenshots' => [[
'path' => 'screenshot/rick-astley.jpg',
'title' => 'Rick Astley',
'description' => 'He\'ll never gonna give you up or let you down',
]]],
],
'screenshots'
);
}
/**
* {@inheritdoc}
*/
protected function getConfiguration(): ConfigurationInterface
{
return new ThemeConfiguration();
}
}

View file

@ -1,136 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Tests\DependencyInjection;
use Matthias\SymfonyConfigTest\PhpUnit\ConfigurationTestCaseTrait;
use PHPUnit\Framework\TestCase;
use Sylius\Bundle\ThemeBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class ConfigurationTest extends TestCase
{
use ConfigurationTestCaseTrait;
/**
* @test
*/
public function it_has_default_context_service_set(): void
{
$this->assertProcessedConfigurationEquals(
[
[],
],
['context' => 'sylius.theme.context.settable'],
'context'
);
}
/**
* @test
*/
public function its_context_cannot_be_empty(): void
{
$this->assertPartialConfigurationIsInvalid(
[
[''],
],
'context'
);
}
/**
* @test
*/
public function its_context_can_be_overridden(): void
{
$this->assertProcessedConfigurationEquals(
[
['context' => 'sylius.theme.context.custom'],
],
['context' => 'sylius.theme.context.custom'],
'context'
);
}
/**
* @test
*/
public function assets_support_is_enabled_by_default()
{
$this->assertProcessedConfigurationEquals([[]], ['assets' => ['enabled' => true]], 'assets');
}
/**
* @test
*/
public function assets_support_may_be_toggled()
{
$this->assertProcessedConfigurationEquals([['assets' => ['enabled' => true]]], ['assets' => ['enabled' => true]], 'assets');
$this->assertProcessedConfigurationEquals([['assets' => []]], ['assets' => ['enabled' => true]], 'assets');
$this->assertProcessedConfigurationEquals([['assets' => null]], ['assets' => ['enabled' => true]], 'assets');
$this->assertProcessedConfigurationEquals([['assets' => ['enabled' => false]]], ['assets' => ['enabled' => false]], 'assets');
$this->assertProcessedConfigurationEquals([['assets' => false]], ['assets' => ['enabled' => false]], 'assets');
}
/**
* @test
*/
public function templating_support_is_enabled_by_default()
{
$this->assertProcessedConfigurationEquals([[]], ['templating' => ['enabled' => true]], 'templating');
}
/**
* @test
*/
public function templating_support_may_be_toggled()
{
$this->assertProcessedConfigurationEquals([['templating' => ['enabled' => true]]], ['templating' => ['enabled' => true]], 'templating');
$this->assertProcessedConfigurationEquals([['templating' => []]], ['templating' => ['enabled' => true]], 'templating');
$this->assertProcessedConfigurationEquals([['templating' => null]], ['templating' => ['enabled' => true]], 'templating');
$this->assertProcessedConfigurationEquals([['templating' => ['enabled' => false]]], ['templating' => ['enabled' => false]], 'templating');
$this->assertProcessedConfigurationEquals([['templating' => false]], ['templating' => ['enabled' => false]], 'templating');
}
/**
* @test
*/
public function translations_support_is_enabled_by_default()
{
$this->assertProcessedConfigurationEquals([[]], ['translations' => ['enabled' => true]], 'translations');
}
/**
* @test
*/
public function translations_support_may_be_toggled()
{
$this->assertProcessedConfigurationEquals([['translations' => ['enabled' => true]]], ['translations' => ['enabled' => true]], 'translations');
$this->assertProcessedConfigurationEquals([['translations' => []]], ['translations' => ['enabled' => true]], 'translations');
$this->assertProcessedConfigurationEquals([['translations' => null]], ['translations' => ['enabled' => true]], 'translations');
$this->assertProcessedConfigurationEquals([['translations' => ['enabled' => false]]], ['translations' => ['enabled' => false]], 'translations');
$this->assertProcessedConfigurationEquals([['translations' => false]], ['translations' => ['enabled' => false]], 'translations');
}
/**
* {@inheritdoc}
*/
protected function getConfiguration(): ConfigurationInterface
{
return new Configuration();
}
}

View file

@ -1,151 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Tests\DependencyInjection\FilesystemSource;
use Matthias\SymfonyConfigTest\PhpUnit\ConfigurationTestCaseTrait;
use PHPUnit\Framework\TestCase;
use Sylius\Bundle\ThemeBundle\Configuration\Filesystem\FilesystemConfigurationSourceFactory;
use Sylius\Bundle\ThemeBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
final class ConfigurationTest extends TestCase
{
use ConfigurationTestCaseTrait;
/**
* @test
*/
public function it_uses_app_themes_filesystem_as_the_default_source(): void
{
$this->assertProcessedConfigurationEquals(
[
['sources' => ['filesystem' => null]],
],
['sources' => ['filesystem' => [
'directories' => ['%kernel.root_dir%/themes'],
'filename' => 'composer.json',
'enabled' => true,
'scan_depth' => null,
]]],
'sources'
);
}
/**
* @test
*/
public function it_allows_an_integer_for_scan_depth(): void
{
$this->assertProcessedConfigurationEquals(
[
['sources' => ['filesystem' => ['scan_depth' => 1]]],
],
['sources' => ['filesystem' => [
'directories' => ['%kernel.root_dir%/themes'],
'filename' => 'composer.json',
'enabled' => true,
'scan_depth' => 1,
]]],
'sources'
);
}
/**
* @test
*/
public function it_does_not_add_default_theme_directories_if_there_are_some_defined_by_user(): void
{
$this->assertProcessedConfigurationEquals(
[
['sources' => ['filesystem' => ['directories' => ['/custom/path', '/custom/path2']]]],
],
['sources' => ['filesystem' => [
'directories' => ['/custom/path', '/custom/path2'],
'filename' => 'composer.json',
'enabled' => true,
'scan_depth' => null,
]]],
'sources.filesystem'
);
}
/**
* @test
*/
public function it_uses_the_last_theme_directories_passed_and_rejects_the_other_ones(): void
{
$this->assertProcessedConfigurationEquals(
[
['sources' => ['filesystem' => ['directories' => ['/custom/path', '/custom/path2']]]],
['sources' => ['filesystem' => ['directories' => ['/last/custom/path']]]],
],
['sources' => ['filesystem' => [
'directories' => ['/last/custom/path'],
'filename' => 'composer.json',
'enabled' => true,
'scan_depth' => null,
]]],
'sources.filesystem'
);
}
/**
* @test
*/
public function it_is_invalid_to_pass_a_string_as_theme_directories(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['directories' => '/string/not/array'],
],
'sources.filesystem'
);
}
/**
* @test
*/
public function it_is_invalid_to_pass_a_string_as_scan_depth(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['sources' => ['filesystem' => ['directories' => ['/custom/path', '/custom/path2'], 'scan_depth' => 'test']]],
],
'sources.filesystem'
);
}
/**
* @test
*/
public function it_throws_an_error_if_trying_to_set_theme_directories_to_an_empty_array(): void
{
$this->assertPartialConfigurationIsInvalid(
[
['directories' => []],
],
'sources.filesystem'
);
}
/**
* {@inheritdoc}
*/
protected function getConfiguration(): ConfigurationInterface
{
return new Configuration([
new FilesystemConfigurationSourceFactory(),
]);
}
}

View file

@ -1,46 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Tests\DependencyInjection\FilesystemSource;
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
use Sylius\Bundle\ThemeBundle\Configuration\Filesystem\FilesystemConfigurationSourceFactory;
use Sylius\Bundle\ThemeBundle\DependencyInjection\SyliusThemeExtension;
final class SyliusThemeExtensionTest extends AbstractExtensionTestCase
{
/**
* @test
*/
public function it_does_not_register_a_provider_while_it_is_disabled(): void
{
$this->load(['sources' => ['filesystem' => false]]);
$this->assertContainerBuilderHasServiceDefinitionWithArgument(
'sylius.theme.configuration.provider',
0,
[]
);
}
/**
* {@inheritdoc}
*/
protected function getContainerExtensions(): array
{
$themeExtension = new SyliusThemeExtension();
$themeExtension->addConfigurationSourceFactory(new FilesystemConfigurationSourceFactory());
return [$themeExtension];
}
}

View file

@ -1,82 +0,0 @@
<?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.
*/
declare(strict_types=1);
namespace Sylius\Bundle\ThemeBundle\Tests\DependencyInjection;
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
use Sylius\Bundle\ThemeBundle\DependencyInjection\SyliusThemeExtension;
final class SyliusThemeExtensionTest extends AbstractExtensionTestCase
{
/**
* @test
*/
public function it_aliases_configured_theme_context_service(): void
{
$this->load(['context' => 'sylius.theme.context.custom']);
$this->assertContainerBuilderHasAlias('sylius.context.theme', 'sylius.theme.context.custom');
}
/**
* @test
*/
public function it_loads_all_the_supported_features_by_default(): void
{
$this->load([]);
$this->assertContainerBuilderHasService('sylius.theme.asset.assets_installer');
$this->assertContainerBuilderHasService('sylius.theme.templating.locator');
$this->assertContainerBuilderHasService('sylius.theme.translation.translator');
}
/**
* @test
*/
public function it_does_not_load_assets_support_if_its_disabled(): void
{
$this->load(['assets' => ['enabled' => false]]);
$this->assertContainerBuilderNotHasService('sylius.theme.asset.assets_installer');
}
/**
* @test
*/
public function it_does_not_load_templating_support_if_its_disabled(): void
{
$this->load(['templating' => ['enabled' => false]]);
$this->assertContainerBuilderNotHasService('sylius.theme.templating.locator');
}
/**
* @test
*/
public function it_does_not_load_translations_support_if_its_disabled(): void
{
$this->load(['translations' => ['enabled' => false]]);
$this->assertContainerBuilderNotHasService('sylius.theme.translation.translator');
}
/**
* {@inheritdoc}
*/
protected function getContainerExtensions(): array
{
return [
new SyliusThemeExtension(),
];
}
}

View file

@ -1,3 +0,0 @@
test:
theme_bundle: 'THEME/BUNDLE_NAME/translations'
theme: 'THEME/BUNDLE_NAME/translations'

View file

@ -1 +0,0 @@
TestBundle:Templating:bothThemesTemplate.txt.twig|sylius/first-test-theme

View file

@ -1 +0,0 @@
TestBundle:Templating:vanillaOverriddenThemeTemplate.txt.twig|sylius/first-test-theme

View file

@ -1,17 +0,0 @@
{
"name": "sylius/first-test-theme",
"authors": [
{
"name": "Krzysztof Krawczyk",
"email": "krzysztof.krawczyk@example.com"
}
],
"extra": {
"sylius-theme": {
"title": "Sylius First Theme",
"parents": [
"sylius/second-test-theme"
]
}
}
}

View file

@ -1,2 +0,0 @@
test:
theme: 'THEME/translations'

View file

@ -1 +0,0 @@
:Templating:bothThemesTemplate.txt.twig|sylius/first-test-theme

View file

@ -1 +0,0 @@
This should be overridden by first theme

View file

@ -1,5 +0,0 @@
test:
theme_bundle: 'That should be overridden by first test theme.'
theme: 'That should be overridden by first test theme.'
parent_theme_bundle: 'PARENT_THEME/BUNDLE_NAME/translations'
parent_theme: 'PARENT_THEME/BUNDLE_NAME/translations'

Some files were not shown because too many files have changed in this diff Show more