Skip to content

Commit

Permalink
Merge pull request #28 from beniaminblaszkiewicz/OPSRC-441_feature_se…
Browse files Browse the repository at this point in the history
…t_template_per_catalog

OPSRC-441 Add choices templates
  • Loading branch information
KrisFlorq authored Jan 26, 2022
2 parents 2d5b7d1 + 0bb1107 commit cc7b5e6
Show file tree
Hide file tree
Showing 13 changed files with 344 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ For catalog You can configure:
* when it should be shown - this is useful for time restricted special offers or promotions
* there is set of rules that restrict which products will be shown inside, they can be combined using AND or OR.
* there is another set of rules - used to restrict products associated with given catalog - it can be shown on product details page
* templates for each catalog

- [Installation](doc/installation.md)
- [Testing & running the plugin](doc/installation.md#testing--running-the-plugin)
Expand Down
17 changes: 17 additions & 0 deletions doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ bitbag_sylius_catalog_plugin:
To display catalogs in product details You need to override product details template, for example with template provided as a part of test application in
`vendor/bitbag/catalog-plugin/tests/Application/templates/bundles/SyliusShopBundle/Product/show.html.twig`

Create directory for yours catalog template, by default `catalog`
```bash
$ mkdir -p templates/catalog
```
If you want to have product catalog templates in different directory, you can change `catalog` directory by changing `templates_dir`.
```yaml
# config/packages/bitbag_sylius_catalog_plugin.yaml
bit_bag_sylius_catalog:
templates_dir: 'your_catalog_name'
```
Then your templates for catalog will be stored at `%kernel.project_dir%/Templates/your_catalog_name`.
Default template for product catalog is `@BitBagSyliusCatalogPlugin/Catalog/Templates/showProducts.html.twig`



Finish the installation by updating the database schema and installing assets:
```
$ symfony console doctrine:migrations:diff
Expand Down
91 changes: 91 additions & 0 deletions spec/Choices/CatalogMapperSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

/*
* This file was created by developers working at BitBag
* Do you need more information about us and what we do? Visit our https://bitbag.io website!
* We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
*/

declare(strict_types=1);

namespace spec\BitBag\SyliusCatalogPlugin\Choices;

use BitBag\SyliusCatalogPlugin\Choices\CatalogInterface;
use BitBag\SyliusCatalogPlugin\Choices\CatalogMapper;
use BitBag\SyliusCatalogPlugin\Choices\CatalogMapperInterface;
use PhpSpec\ObjectBehavior;
use Symfony\Component\Finder\SplFileInfo;

final class CatalogMapperSpec extends ObjectBehavior
{
private const CATALOG_NAME = 'catalog';

public function let(): void
{
$this->beConstructedWith(self::CATALOG_NAME);
}

public function it_is_initializable(): void
{
$this->shouldHaveType(CatalogMapper::class);
}

public function it_implements_catalog_mapper_interface(): void
{
$this->shouldHaveType(CatalogMapperInterface::class);
}

public function it_returns_array_of_templates_from_catalog_dir_with_default_one(
SplFileInfo $file1,
SplFileInfo $file2
): void {
$files = new \ArrayIterator([
$file1->getWrappedObject(),
$file2->getWrappedObject(),
]);

$file1->getBasename('.html.twig')->willReturn('one');
$file1->getBasename()->willReturn('one.html.twig');

$file2->getBasename('.html.twig')->willReturn('two');
$file2->getBasename()->willReturn('two.html.twig');

$templates = [
'one' => self::CATALOG_NAME . '/one.html.twig',
'two' => self::CATALOG_NAME . '/two.html.twig',
];

$this->map($files)->shouldReturn(array_merge(CatalogInterface::DEFAULT_TEMPLATE, $templates));
}

public function it_returns_array_of_templates_from_catalog_dir_with_first_default(
SplFileInfo $file1,
SplFileInfo $file2,
SplFileInfo $default
): void {
$files = new \ArrayIterator([
$file1->getWrappedObject(),
$file2->getWrappedObject(),
$default->getWrappedObject(),
]);

$file1->getBasename('.html.twig')->willReturn('one');
$file1->getBasename()->willReturn('one.html.twig');

$file2->getBasename('.html.twig')->willReturn('two');
$file2->getBasename()->willReturn('two.html.twig');

$default->getBasename('.html.twig')->willReturn('default');
$default->getBasename()->willReturn('default.html.twig');

$templates = [
'one' => self::CATALOG_NAME . '/one.html.twig',
'two' => self::CATALOG_NAME . '/two.html.twig',
'default' => self::CATALOG_NAME . '/default.html.twig',
];

if (in_array(array_key_first(CatalogInterface::DEFAULT_TEMPLATE), array_keys($templates))) {
$this->map($files)->shouldReturn(array_merge(['default' => $templates['default']], $templates));
}
}
}
75 changes: 75 additions & 0 deletions spec/Choices/CatalogSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
/*
* This file has been created by developers from BitBag.
* Feel free to contact us once you face any issues or want to start
* another great project.
* You can find more information about us on https://bitbag.io and write us
* an email on [email protected].
*/
declare(strict_types=1);

namespace spec\BitBag\SyliusCatalogPlugin\Choices;

use BitBag\SyliusCatalogPlugin\Choices\Catalog;
use BitBag\SyliusCatalogPlugin\Choices\CatalogInterface;
use BitBag\SyliusCatalogPlugin\Choices\CatalogMapperInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;

final class CatalogSpec extends ObjectBehavior
{
private const FULL_TEMPLATE_PATH = 'spec/test';

public function let(CatalogMapperInterface $catalogMapper, Finder $finder): void
{
$this->beConstructedWith(self::FULL_TEMPLATE_PATH, $catalogMapper, $finder);
}

public function it_is_initializable(): void
{
$this->shouldHaveType(Catalog::class);
}

public function it_implements_catalog_interface(): void
{
$this->shouldHaveType(CatalogInterface::class);
}

public function it_returns_default_template_if_directory_doesnt_exist(
Finder $finder
): void {
$finder->files()->willReturn($finder);
$finder->in(Argument::type('string'))->willReturn($finder);
$finder->name('*.html.twig')->willReturn($finder);
$finder->depth(0)->willThrow(DirectoryNotFoundException::class);

$this->getTemplates()->shouldReturn(CatalogInterface::DEFAULT_TEMPLATE);
}

public function it_returns_default_template_if_directory_doesnt_contain_twig_files(
Finder $finder
): void {
if (!is_dir(self::FULL_TEMPLATE_PATH)) {
mkdir(self::FULL_TEMPLATE_PATH, 0777, true);
}
$finder->files()->willReturn($finder);
$finder->in(self::FULL_TEMPLATE_PATH)->willReturn($finder);
$finder->name('*.html.twig')->willReturn($finder);
$finder->depth(0)->willReturn($finder);

$finder->hasResults()->willReturn(false);

$this->getTemplates()->shouldReturn(CatalogInterface::DEFAULT_TEMPLATE);

$this->rrmdir(self::FULL_TEMPLATE_PATH);
}

private function rrmdir(string $directory): bool
{
array_map(fn (string $file) => is_dir($file) ? $this->rrmdir($file) : unlink($file), glob($directory . '/' . '*'));

return rmdir($directory);
}
}
39 changes: 34 additions & 5 deletions src/Choices/Catalog.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,41 @@

namespace BitBag\SyliusCatalogPlugin\Choices;

final class Catalog
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;

final class Catalog implements CatalogInterface
{
public static function getTemplates(): array
private string $fullTemplatePath;

private CatalogMapperInterface $catalogMapper;

private Finder $finder;

public function __construct(string $fullTemplatePath, CatalogMapperInterface $catalogMapper, Finder $finder)
{
return [
'bitbag_sylius_catalog_plugin.ui.form.catalog.default_template' => '@BitBagSyliusCatalogPlugin/Catalog/Templates/showProducts.html.twig',
];
$this->fullTemplatePath = $fullTemplatePath;
$this->catalogMapper = $catalogMapper;
$this->finder = $finder;
}

public function getTemplates(): array
{
try {
$this->finder
->files()
->in($this->fullTemplatePath)
->name('*.html.twig')
->depth(0)
;
} catch (DirectoryNotFoundException $directoryNotFoundException) {
return self::DEFAULT_TEMPLATE;
}

if (!$this->finder->hasResults()) {
return self::DEFAULT_TEMPLATE;
}

return $this->catalogMapper->map($this->finder->getIterator());
}
}
18 changes: 18 additions & 0 deletions src/Choices/CatalogInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/*
* This file has been created by developers from BitBag.
* Feel free to contact us once you face any issues or want to start
* another great project.
* You can find more information about us on https://bitbag.io and write us
* an email on [email protected].
*/
declare(strict_types=1);

namespace BitBag\SyliusCatalogPlugin\Choices;

interface CatalogInterface
{
public const DEFAULT_TEMPLATE = ['default' => '@BitBagSyliusCatalogPlugin/Catalog/Templates/showProducts.html.twig'];

public function getTemplates(): array;
}
34 changes: 34 additions & 0 deletions src/Choices/CatalogMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file was created by developers working at BitBag
* Do you need more information about us and what we do? Visit our https://bitbag.io website!
* We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
*/

declare(strict_types=1);

namespace BitBag\SyliusCatalogPlugin\Choices;

final class CatalogMapper implements CatalogMapperInterface
{
private string $catalogName;

public function __construct(string $catalogName)
{
$this->catalogName = $catalogName;
}

public function map(iterable $files): array
{
$templates = [];
foreach ($files as $file) {
$templates[$file->getBasename('.html.twig')] = $this->catalogName . '/' . $file->getBasename();
}
if (in_array(array_key_first(CatalogInterface::DEFAULT_TEMPLATE), array_keys($templates))) {
return array_merge(['default' => $templates['default']], $templates);
}

return array_merge(CatalogInterface::DEFAULT_TEMPLATE, $templates);
}
}
15 changes: 15 additions & 0 deletions src/Choices/CatalogMapperInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
/*
* This file was created by developers working at BitBag
* Do you need more information about us and what we do? Visit our https://bitbag.io website!
* We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
*/

declare(strict_types=1);

namespace BitBag\SyliusCatalogPlugin\Choices;

interface CatalogMapperInterface
{
public function map(iterable $files): array;
}
5 changes: 4 additions & 1 deletion src/DependencyInjection/BitBagSyliusCatalogExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ public function load(array $config, ContainerBuilder $container): void
$container->getDefinition('bitbag_sylius_catalog_plugin.form.type.catalog')
->setArgument(1, sprintf('%%bitbag_sylius_catalog_plugin.catalog_sorts.%s%%', $config['driver']))
);

$container->setParameter('bitbag_sylius_catalog_plugin.parameters.templates_dir', $config['templates_dir']);

}

public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
{
return new Configuration();
return new Configuration($container->getParameter('kernel.project_dir'));
}

public function prepend(ContainerBuilder $container): void
Expand Down
34 changes: 30 additions & 4 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,45 @@

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

final class Configuration implements ConfigurationInterface
{
private string $projectDir;

public function __construct(string $projectDir)
{
$this->projectDir = $projectDir;
}

public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('bitbag_sylius_catalog_plugin');
$rootNode = $treeBuilder->getRootNode();

$rootNode
->children()
->enumNode('driver')
->values(['doctrine', 'elasticsearch'])
->defaultValue('doctrine')
->enumNode('driver')
->values(['doctrine', 'elasticsearch'])
->defaultValue('doctrine')
->end()
->scalarNode('templates_dir')
->defaultValue('catalog')
->cannotBeEmpty()
->validate()
->always(function ($value) {
if (!is_string($value)) {
throw new InvalidConfigurationException('templates_dir must be string');
}

$fullDirPath = $this->projectDir.'/templates/'.$value;

if (!is_dir($fullDirPath)) {
throw new InvalidConfigurationException(sprintf('%s is not valid directory', $fullDirPath));
}
return $value;
})
->end()
->end()
->end()
;

Expand Down
Loading

0 comments on commit cc7b5e6

Please sign in to comment.