Skip to content

Commit

Permalink
Merge pull request #9173 from mickaelandrieu/improved-module-template…
Browse files Browse the repository at this point in the history
…-loader

Registered all namespaces in ModuleTemplateLoader class
  • Loading branch information
PierreRambaud committed Jun 12, 2018
2 parents da6da3f + 8e3eaf0 commit 1c6d820
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 72 deletions.
9 changes: 8 additions & 1 deletion src/PrestaShopBundle/Resources/config/services/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ services:

prestashop.twig.modules.loader:
class: 'PrestaShopBundle\Twig\Locator\ModuleTemplateLoader'
arguments: ['@=service("prestashop.module_kernel.repository").getActiveModulesPaths()']
arguments:
-
'PrestaShop': ''
'Product': '/Admin/Product'
'Twig': '/Admin/TwigTemplateForm'
'AdvancedParameters': '/Admin/Configure/AdvancedParameters'
'ShopParameters': '/Admin/Configure/ShopParameters'
- '@=service("prestashop.module_kernel.repository").getActiveModulesPaths()'
tags:
- { name: twig.loader, priority: 1}
Original file line number Diff line number Diff line change
Expand Up @@ -23,117 +23,118 @@
* International Registered Trademark & Property of PrestaShop SA
*#}
<tbody
{% if activate_drag_and_drop and has_category_filter %}class="sortable"{% endif %}
last_sql="{{ last_sql_query|escape('html_attr') }}"
{% if activate_drag_and_drop and has_category_filter %}class="sortable"{% endif %}
last_sql="{{ last_sql_query|escape('html_attr') }}"
>
{% for product in products %}
{% for product in products %}
{% block product_catalog_form_table_row %}
<tr data-uniturl="{{ product.unit_action_url|default('#') }}" data-product-id="{{ product.id_product }}">
<td class="checkbox-column form-group">
<div class="md-checkbox md-checkbox-inline">
<label>
<input type="checkbox" id="bulk_action_selected_products-{{ product.id_product }}" name="bulk_action_selected_products[]" value="{{ product.id_product }}">
<i class="md-checkbox-control"></i>
</label>
</div>
<div class="md-checkbox md-checkbox-inline">
<label>
<input type="checkbox" id="bulk_action_selected_products-{{ product.id_product }}" name="bulk_action_selected_products[]" value="{{ product.id_product }}">
<i class="md-checkbox-control"></i>
</label>
</div>
</td>
<td>
<label class="form-check-label" for="bulk_action_selected_products-{{ product.id_product }}">
{{ product.id_product }}
{{ product.id_product }}
</label>
</td>
<td>
<a href="{{ product.url|default('') }}#tab-step1">{{ product.image|raw }}</a>
<a href="{{ product.url|default('') }}#tab-step1">{{ product.image|raw }}</a>
</td>
<td>
<a href="{{ product.url|default('') }}#tab-step1">{{ product.name|default('N/A'|trans({}, 'Admin.Global')) }}</a>
<a href="{{ product.url|default('') }}#tab-step1">{{ product.name|default('N/A'|trans({}, 'Admin.Global')) }}</a>
</td>
<td>
{{ product.reference|default('') }}
{{ product.reference|default('') }}
</td>
<td>
{{ product.name_category|default('') }}
{{ product.name_category|default('') }}
</td>
<td class="text-center">
<a href="{{ product.url|default('') }}#tab-step2">{{ product.price|default('N/A'|trans({}, 'Admin.Global')) }}</a>
<a href="{{ product.url|default('') }}#tab-step2">{{ product.price|default('N/A'|trans({}, 'Admin.Global')) }}</a>
</td>

{% if 'PS_STOCK_MANAGEMENT'|configuration %}
<td class="product-sav-quantity text-center" data-product-quantity-value="{{ product.sav_quantity|default('') }}">
<a href="{{ product.url|default('') }}#tab-step3">
{% if product.sav_quantity is defined and product.sav_quantity > 0 %}
{{ product.sav_quantity }}
{% else %}
{{ product.sav_quantity|default('N/A'|trans({}, 'Admin.Global')) }}
{% endif %}
</a>
</td>
<td class="product-sav-quantity text-center" data-product-quantity-value="{{ product.sav_quantity|default('') }}">
<a href="{{ product.url|default('') }}#tab-step3">
{% if product.sav_quantity is defined and product.sav_quantity > 0 %}
{{ product.sav_quantity }}
{% else %}
{{ product.sav_quantity|default('N/A'|trans({}, 'Admin.Global')) }}
{% endif %}
</a>
</td>
{% else %}
<td></td>
{% endif %}
<td class="text-center">
{% if product.active|default(0) == 0 %}
<a href="#" onclick="unitProductAction(this, 'activate'); return false;">
<i class="material-icons action-disabled">clear</i>
</a>
{% else %}
<a href="#" onclick="unitProductAction(this, 'deactivate'); return false;">
<i class="material-icons action-enabled ">check</i>
</a>
{% endif %}
{% if product.active|default(0) == 0 %}
<a href="#" onclick="unitProductAction(this, 'activate'); return false;">
<i class="material-icons action-disabled">clear</i>
</a>
{% else %}
<a href="#" onclick="unitProductAction(this, 'deactivate'); return false;">
<i class="material-icons action-enabled ">check</i>
</a>
{% endif %}
</td>
{% if product.position is defined %}
<td {% if activate_drag_and_drop %}class="placeholder"{% endif %} style="cursor: pointer; cursor: hand;">
{% if activate_drag_and_drop %}
<big><big>⇅</big></big>
{% endif %}
<span class="position">{{ product.position }}</span>
<input type="hidden" name="mass_edit_action_sorted_products[]" value="{{ product.id_product }}" />
<input type="hidden" name="mass_edit_action_sorted_positions[]" value="{{ product.position }}" />
</td>
<td {% if activate_drag_and_drop %}class="placeholder"{% endif %} style="cursor: pointer; cursor: hand;">
{% if activate_drag_and_drop %}
<big><big>⇅</big></big>
{% endif %}
<span class="position">{{ product.position }}</span>
<input type="hidden" name="mass_edit_action_sorted_products[]" value="{{ product.id_product }}" />
<input type="hidden" name="mass_edit_action_sorted_positions[]" value="{{ product.position }}" />
</td>
{% endif %}
<td class="text-right">
<div class="btn-group-action">

{% set buttons_action = [
{
"href": product.preview_url|default('#'),
"target": "_blank",
"icon": "remove_red_eye",
"label": "Preview"|trans({}, 'Admin.Actions')
}
{
"href": product.preview_url|default('#'),
"target": "_blank",
"icon": "remove_red_eye",
"label": "Preview"|trans({}, 'Admin.Actions')
}
] %}

{% set buttons_action = buttons_action|merge([
{
"onclick": "unitProductAction(this, 'duplicate');",
"icon": "content_copy",
"label": "Duplicate"|trans({}, 'Admin.Actions')
}
{
"onclick": "unitProductAction(this, 'duplicate');",
"icon": "content_copy",
"label": "Duplicate"|trans({}, 'Admin.Actions')
}
]) %}

{% set buttons_action = buttons_action|merge([
{
"onclick": "unitProductAction(this, 'delete');",
"icon": "delete",
"label": "Delete"|trans({}, 'Admin.Actions')
}
{
"onclick": "unitProductAction(this, 'delete');",
"icon": "delete",
"label": "Delete"|trans({}, 'Admin.Actions')
}
]) %}

{% include '@Product/CatalogPage/Forms/form_edit_dropdown.html.twig' with {
'button_id': "product_list_id_" ~ product.id_product ~ "_menu",
'default_item': {
"href": product.url|default('#'),
"icon": "mode_edit"
},
'right': true,
'items': buttons_action
'button_id': "product_list_id_" ~ product.id_product ~ "_menu",
'default_item': {
"href": product.url|default('#'),
"icon": "mode_edit"
},
'right': true,
'items': buttons_action
} %}
</div>
</td>
</tr>
{% else %}
<tr><td colspan="11">
{% endblock %}
{% else %}
<tr><td colspan="11">
{{ "There is no result for this search. Update your filters to view other products."|trans({}, 'Admin.Catalog.Notification') }}
</td></tr>
{% endfor %}
</tbody>
{% endfor %}
18 changes: 15 additions & 3 deletions src/PrestaShopBundle/Twig/Locator/ModuleTemplateLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,34 @@ class ModuleTemplateLoader extends FilesystemLoader
private $rootPath;

/**
* @param array $namespaces A collection of path namespaces with namespace names.
* @param string|array $paths A path or an array of paths where to look for templates
* @param string|null $rootPath The root path common to all relative paths (null for getcwd())
* @param string|null $namespace A path namespace
*/
public function __construct($paths = array(), $rootPath = null, $namespace = 'PrestaShop')
public function __construct(array $namespaces, $paths = array(), $rootPath = null)
{
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
if (false !== $realPath = realpath($rootPath)) {
$this->rootPath = $realPath.DIRECTORY_SEPARATOR;
}

if ($paths) {
$this->registerNamespacesFromConfig($paths, $namespaces);
}
}

/**
* Register namespaces in module and link them to the right paths.
* @param $paths
* @param array $namespaces
*/
private function registerNamespacesFromConfig($paths, array $namespaces)
{
foreach ($namespaces as $namespace => $namespacePath) {
$templatePaths = array();

foreach ($paths as $path) {
if (is_dir($dir = $path . '/views/'. $namespace)) {
if (is_dir($dir = $path . '/views/PrestaShop/' . $namespacePath)) {
$templatePaths[] = $dir;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
List from module 3
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module3
133 changes: 133 additions & 0 deletions tests/PrestaShopBundle/Twig/Locator/ModuleTemplateLoaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/

namespace Tests\PrestaShopBundle\Twig\Locator;

use PrestaShopBundle\Twig\Locator\ModuleTemplateLoader;
use PHPUnit\Framework\TestCase;

/**
* @group sf
*/
class ModuleTemplateLoaderTest extends TestCase
{
/**
* @var TemplateModuleLoader
*/
private $loader;

/**
* {@inheritdoc}
*/
protected function setUp()
{
$namespaces = [
'Product' => 'Admin/Product',
'PrestaShop' => '',
];

$paths = [
__DIR__.'/../Fixtures/module1',
__DIR__.'/../Fixtures/module2',
__DIR__.'/../Fixtures/module3',
];

$rootPath = null;

$this->loader = new ModuleTemplateLoader($namespaces, $paths, $rootPath);
}

/**
* {@inheritdoc}
*/
protected function tearDown()
{
$this->loader = null;
}

public function testGetPaths()
{
self::assertCount(
2,
$this->loader->getPaths('Product'),
'Two templates for the namespace "Product" should be found.'
);

self::assertCount(
3,
$this->loader->getPaths('PrestaShop'),
'One templates should be found.');
}

/**
* @dataProvider getSourceContextsProvider
* @param string $sourceContent The template file content.
* @param string $twigPathAsked The Twig path asked during Twig template rendering.
* @param string $successMessage In case of failure, describe what is expected.
*/
public function testGetSourceContext($sourceContent, $twigPathAsked, $successMessage)
{
self::assertEquals(
$sourceContent . PHP_EOL,
$this->loader->getSourceContext($twigPathAsked)->getCode(),
$successMessage
);
}

/**
* @return array
*/
public function getSourceContextsProvider()
{
return [
['module1', '@Product/test.html.twig', 'Module 1 wins as Module 3 is loaded after.'],
['module1', '@PrestaShop/Admin/Product/test.html.twig', 'PrestaShop is the main namespace.'],
['List from module 3', '@Product/ProductPage/Lists/list.html.twig', 'Module 3 templates are available.'],
['module2', '@PrestaShop/test.html.twig', 'Module 2 templates are availables.'],
];
}

public function testEmptyConstructor()
{
$loader = new ModuleTemplateLoader([]);

self::assertEquals(array(), $loader->getPaths());
}

/**
* @throws \Twig_Error_Loader
*/
public function testGetNamespaces()
{
$loader = new ModuleTemplateLoader([]);

self::assertEquals([], $loader->getNamespaces());

$loader->addPath(sys_get_temp_dir(), 'named');

self::assertEquals(['named'], $loader->getNamespaces());
}
}

0 comments on commit 1c6d820

Please sign in to comment.