diff --git a/features/domain/category/category_link.feature b/features/domain/category/category_link.feature
index 771f75a965..6c92377957 100644
--- a/features/domain/category/category_link.feature
+++ b/features/domain/category/category_link.feature
@@ -7,4 +7,4 @@ Feature: In order that a customer can visit the category page
And the site has a category "Shirts"
Scenario: Create URL for product
- Then the generated url for object should be "/en/shop/shirts~c%id"
+ Then the generated url for object should be "/en/shirts"
diff --git a/features/domain/product/product_link.feature b/features/domain/product/product_link.feature
index d8bc6f096d..c0eae0ee09 100644
--- a/features/domain/product/product_link.feature
+++ b/features/domain/product/product_link.feature
@@ -8,4 +8,4 @@ Feature: In order that a customer can visit the product page
Then the product "Shoe" should be priced at "100"
Scenario: Create URL for product
- Then the generated url for object should be "/en/shop/shoe~p%id"
+ Then the generated url for object should be "/en/shoe"
diff --git a/features/ui/frontend/product/view_product_via_link.feature b/features/ui/frontend/product/view_product_via_link.feature
index fb90f5d1c2..06e182eb08 100644
--- a/features/ui/frontend/product/view_product_via_link.feature
+++ b/features/ui/frontend/product/view_product_via_link.feature
@@ -8,7 +8,7 @@ Feature: Viewing a product details using it's link
Scenario: View product via link
Given the site has a product "T-Shirt"
And the product is active and published and available for store "Austria"
- When I open the page "en/shop/t-shirt~p%id%" for this product
+ When I open the page "en/t-shirt" for this product
Then I should be on the product's detail page
Then I should see the product name "T-Shirt"
diff --git a/src/CoreShop/Behat/Context/Cli/InstallerContext.php b/src/CoreShop/Behat/Context/Cli/InstallerContext.php
index ff817a490a..5390b0972c 100644
--- a/src/CoreShop/Behat/Context/Cli/InstallerContext.php
+++ b/src/CoreShop/Behat/Context/Cli/InstallerContext.php
@@ -107,10 +107,7 @@ public function commandSuccess()
*/
private function iExecuteCommandAndConfirm($name)
{
- try {
- $this->tester->setInputs(['y']);
- $this->tester->execute(['command' => $name]);
- } catch (\Exception $e) {
- }
+ $this->tester->setInputs(['y']);
+ $this->tester->execute(['command' => $name]);
}
}
diff --git a/src/CoreShop/Behat/Context/Domain/LinkGeneratorContext.php b/src/CoreShop/Behat/Context/Domain/LinkGeneratorContext.php
index 3cd0d7eeab..85c0f4bd9d 100644
--- a/src/CoreShop/Behat/Context/Domain/LinkGeneratorContext.php
+++ b/src/CoreShop/Behat/Context/Domain/LinkGeneratorContext.php
@@ -37,7 +37,6 @@ public function __construct(SharedStorageInterface $sharedStorage, LinkGenerator
public function theGeneratedUrlForObjectShouldBe(Concrete $object, $url)
{
$generatedUrl = $this->linkGenerator->generate($object, null, ['_locale' => 'en']);
- $url = str_replace('%id', (string)$object->getId(), $url);
Assert::eq(
$generatedUrl,
@@ -56,7 +55,6 @@ public function theGeneratedUrlForObjectShouldBe(Concrete $object, $url)
public function theGeneratedUrlForObjectWithRouteShouldBe(Concrete $object, $routeName, $url)
{
$generatedUrl = $this->linkGenerator->generate($object, $routeName, ['_locale' => 'en']);
- $url = str_replace('%id', (string)$object->getId(), $url);
Assert::eq(
$generatedUrl,
diff --git a/src/CoreShop/Behat/Context/Ui/Domain/PaymentController.php b/src/CoreShop/Behat/Context/Ui/Domain/PaymentController.php
index c8a98bfb36..377607ac1a 100644
--- a/src/CoreShop/Behat/Context/Ui/Domain/PaymentController.php
+++ b/src/CoreShop/Behat/Context/Ui/Domain/PaymentController.php
@@ -86,10 +86,6 @@ public function iOpenCartSummaryPage(PaymentInterface $payment)
* @var Response $result
*/
foreach ($responses as $index => $result) {
- echo "Request:" . $requests[$index]->getUri() . PHP_EOL;
- echo (string)$result->getBody();
- echo PHP_EOL;
-//
Assert::eq(
$result->getStatusCode(),
200,
diff --git a/src/CoreShop/Behat/Context/Ui/Frontend/ProductContext.php b/src/CoreShop/Behat/Context/Ui/Frontend/ProductContext.php
index 301e0a8d18..983b067154 100644
--- a/src/CoreShop/Behat/Context/Ui/Frontend/ProductContext.php
+++ b/src/CoreShop/Behat/Context/Ui/Frontend/ProductContext.php
@@ -45,8 +45,6 @@ public function __construct(
*/
public function iOpenPage($url, ProductInterface $product)
{
- $url = str_replace('%id%', (string)$product->getId(), $url);
-
$this->productPage->tryToOpenWithUri($url);
}
diff --git a/src/CoreShop/Behat/Page/Frontend/ProductPage.php b/src/CoreShop/Behat/Page/Frontend/ProductPage.php
index d191d75f40..3d7c51d786 100644
--- a/src/CoreShop/Behat/Page/Frontend/ProductPage.php
+++ b/src/CoreShop/Behat/Page/Frontend/ProductPage.php
@@ -20,10 +20,7 @@
class ProductPage extends AbstractFrontendPage implements ProductPageInterface
{
- public function getRouteName(): string
- {
- return 'coreshop_product_detail';
- }
+ use SluggablePageTrait;
public function getContent(): string
{
diff --git a/src/CoreShop/Behat/Page/Frontend/SluggablePageTrait.php b/src/CoreShop/Behat/Page/Frontend/SluggablePageTrait.php
new file mode 100644
index 0000000000..f6b1fa693e
--- /dev/null
+++ b/src/CoreShop/Behat/Page/Frontend/SluggablePageTrait.php
@@ -0,0 +1,28 @@
+ [
- 'Small',
- 'Ergonomic',
- 'Rustic',
- 'Intelligent',
- 'Gorgeous',
- 'Incredible',
- 'Fantastic',
- 'Practical',
- 'Sleek',
- 'Awesome',
- 'Enormous',
- 'Mediocre',
- 'Synergistic',
- 'Heavy Duty',
- 'Lightweight',
- 'Aerodynamic',
- 'Durable',
- ],
- 'material' => [
- 'Steel',
- 'Wooden',
- 'Concrete',
- 'Plastic',
- 'Cotton',
- 'Granite',
- 'Rubber',
- 'Leather',
- 'Silk',
- 'Wool',
- 'Linen',
- 'Marble',
- 'Iron',
- 'Bronze',
- 'Copper',
- 'Aluminum',
- 'Paper',
- ],
- 'product' => [
- 'Chair',
- 'Car',
- 'Computer',
- 'Gloves',
- 'Pants',
- 'Shirt',
- 'Table',
- 'Shoes',
- 'Hat',
- 'Plate',
- 'Knife',
- 'Bottle',
- 'Coat',
- 'Lamp',
- 'Keyboard',
- 'Bag',
- 'Bench',
- 'Clock',
- 'Watch',
- 'Wallet',
- ],
- ];
- protected static $promotionCode = [
- 'adjective' => [
- 'Amazing',
- 'Awesome',
- 'Cool',
- 'Good',
- 'Great',
- 'Incredible',
- 'Killer',
- 'Premium',
- 'Special',
- 'Stellar',
- 'Sweet',
- ],
- 'noun' => ['Code', 'Deal', 'Discount', 'Price', 'Promo', 'Promotion', 'Sale', 'Savings'],
- ];
-
- public function promotionCode(int $digits = 6): string
- {
- return static::randomElement(static::$promotionCode['adjective'])
- . static::randomElement(static::$promotionCode['noun'])
- . $this->generator->randomNumber($digits, true);
- }
-
- public function department(int $max = 3, bool $fixedAmount = false): string
- {
- $categories = [];
- if (!$fixedAmount) {
- $max = mt_rand(1, $max);
- }
- $uniqueGenerator = $this->generator->unique(true);
- for ($i = 0; $i < $max; $i++) {
- $categories[] = $uniqueGenerator->category;
- }
- if (count($categories) >= 2) {
- $commaSeparatedCategories = implode(', ', array_slice($categories, 0, -1));
- $categories = [
- $commaSeparatedCategories,
- end($categories),
- ];
- }
-
- return implode(' & ', $categories);
- }
-
- public function category(): string
- {
- return static::randomElement(static::$department);
- }
-
- public function productName(): string
- {
- return static::randomElement(static::$productName['adjective'])
- . ' ' . static::randomElement(static::$productName['material'])
- . ' ' . static::randomElement(static::$productName['product']);
- }
-}
diff --git a/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/AbstractProductFixture.php b/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/AbstractProductFixture.php
index b53fd569b3..0b0ea690ff 100644
--- a/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/AbstractProductFixture.php
+++ b/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/AbstractProductFixture.php
@@ -14,7 +14,6 @@
namespace CoreShop\Bundle\CoreBundle\Fixtures\Data\Demo;
-use CoreShop\Bundle\CoreBundle\Faker\Commerce;
use CoreShop\Bundle\FixtureBundle\Fixture\VersionedFixtureInterface;
use CoreShop\Component\Core\Model\CategoryInterface;
use CoreShop\Component\Core\Model\ProductInterface;
@@ -26,6 +25,7 @@
use Faker\Provider\Lorem;
use Pimcore\Model\Asset;
use Pimcore\Model\DataObject\Service;
+use Pimcore\Tool;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpKernel\KernelInterface;
@@ -34,6 +34,509 @@ abstract class AbstractProductFixture extends AbstractFixture implements Contain
{
use ContainerAwareTrait;
+ protected static array $names = [
+ [
+ "de" => [
+ "name" => "Schwerlast Leder Brieftasche",
+ "description" => "Minus voluptatem asperiores quod excepturi quis. Quod non amet explicabo praesentium similique minima numquam corporis.",
+ ],
+ "en" => [
+ "name" => "Heavy Duty Leather Wallet",
+ "description" => "Debitis deserunt sunt voluptas neque voluptas molestias aut. Eligendi pariatur voluptatem voluptatum autem vel in. Quo labore modi facere qui earum aut. Nemo possimus est debitis.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Leicht Baumwolle Hose",
+ "description" => "Labore itaque et quia. Ad rerum reiciendis consequuntur. Incidunt totam aut qui voluptas. Nemo culpa dolorem ut eos suscipit.",
+ ],
+ "en" => [
+ "name" => "Lightweight Cotton Pants",
+ "description" => "Voluptas minus eos eveniet beatae est repudiandae ut. Deleniti exercitationem id incidunt voluptas. Aut facere voluptatem aut possimus sed est. Sint quia voluptas quisquam earum.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Fantastisch Gummi Wagen",
+ "description" => "Sint id harum autem nisi optio sunt. Quis voluptatem et iure reiciendis dolores pariatur. Itaque dolore vel dolorum id sunt quasi aperiam. Quia id porro eveniet consequatur.",
+ ],
+ "en" => [
+ "name" => "Fantastic Rubber Car",
+ "description" => "Sint doloremque itaque aut voluptate maiores ut. Odit delectus enim aut quis. Omnis expedita assumenda velit possimus recusandae animi deserunt. Placeat qui possimus rerum architecto architecto ut.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Enorm Papier Teller",
+ "description" => "Saepe vel earum soluta sit. Nam voluptatem non aliquam molestias explicabo suscipit qui. Dolorem aliquid et aut. Dicta similique totam culpa.",
+ ],
+ "en" => [
+ "name" => "Enormous Paper Plate",
+ "description" => "Porro delectus rem labore beatae dicta ullam aut. Alias modi amet deleniti neque optio libero. Repellendus mollitia quod pariatur quod iure.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Aluminium Mantel",
+ "description" => "Dolores doloremque repudiandae et ducimus aspernatur ut. Illo eum expedita quibusdam minima vel. Sint iste ratione rerum voluptatem voluptatum et fuga aut. Qui in aspernatur aut est numquam non et.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Aluminum Coat",
+ "description" => "Voluptatibus sit et quas eos. Eaque tenetur enim reprehenderit maxime aut consequatur velit ducimus. Ut eum qui esse commodi.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Genial Papier Schuhe",
+ "description" => "Inventore distinctio maiores ea animi non. Quasi tempora tenetur non. Non voluptatem libero possimus asperiores. Itaque consequatur autem consectetur sequi aut.",
+ ],
+ "en" => [
+ "name" => "Awesome Paper Shoes",
+ "description" => "Aut quasi minus et aut incidunt. Ratione recusandae ipsa temporibus magnam quis molestiae. Placeat nihil aperiam alias et.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Beton Messer",
+ "description" => "Est iste suscipit est vero. Qui nam aut voluptate voluptatem error enim et. Ut dolores facilis reiciendis autem. Dicta commodi impedit non consequuntur quia aut accusamus.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Concrete Knife",
+ "description" => "Dolores deleniti aut quisquam est aut. Vero ut omnis eligendi itaque consequuntur cum. Itaque repellat qui cum minus soluta consequatur.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Praktisch Baumwolle Tasche",
+ "description" => "Non asperiores aliquid ut est omnis. Eligendi vel eum aut aliquid tenetur. Quam amet facilis provident deserunt beatae maiores dolorum. Earum aut ut eligendi et in.",
+ ],
+ "en" => [
+ "name" => "Practical Cotton Bag",
+ "description" => "At est totam debitis sit quo natus nulla voluptatibus. Magnam nisi atque corrupti. Voluptas est culpa eligendi eius eum.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Stahl Brieftasche",
+ "description" => "Aliquam consequuntur sed omnis tempore ut consequatur. Sed laboriosam ex nostrum nemo ad at aliquid consequatur.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Steel Wallet",
+ "description" => "Sit corporis totam eos rerum qui. Enim cupiditate soluta reiciendis possimus dolor non. Reiciendis eos et error maxime dolorem quia et eaque.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Ergonomisch Papier Hut",
+ "description" => "Maiores tempora quo enim repellendus. Qui porro voluptates et quod. Et magni totam est est quos nobis ea. Nihil ducimus voluptas id nihil soluta.",
+ ],
+ "en" => [
+ "name" => "Ergonomic Paper Hat",
+ "description" => "Similique pariatur perferendis illo voluptatibus velit cum. Et dolor natus ab modi ipsum magnam enim. Aliquam asperiores doloremque vero aut corporis quis.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Praktisch Eisen Handschuhe",
+ "description" => "Incidunt temporibus voluptatem et qui eos. Dolores placeat similique provident in quasi repellendus. Consequatur similique dolore vel repudiandae accusantium dolores error.",
+ ],
+ "en" => [
+ "name" => "Practical Iron Gloves",
+ "description" => "Dolor vitae aut cum sequi voluptatem debitis vitae saepe. Est sint rerum facere vel. Amet ab voluptatem beatae consequatur libero et eligendi. Ut eos non pariatur.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Leicht Papier Messer",
+ "description" => "Reiciendis quo vel tempora facere unde ut et. A aut earum harum quasi animi. Architecto sunt eos dolores.",
+ ],
+ "en" => [
+ "name" => "Lightweight Paper Knife",
+ "description" => "Et aut ut commodi vero aliquam. Voluptatem asperiores eaque iste quia praesentium est asperiores. Dolor et maxime illum quo error est et. Aut non qui unde eos.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Glatt Stahl Mantel",
+ "description" => "Sunt non voluptas rerum qui tenetur dolor repellat. Ipsam harum quod consequatur et qui non et. Ut consequatur fugiat error voluptas vero totam in nihil.",
+ ],
+ "en" => [
+ "name" => "Sleek Steel Coat",
+ "description" => "Et commodi dolores animi quia et incidunt et. Animi qui amet eaque et. Repudiandae aut enim vel et facilis praesentium. Sit minima eaque distinctio alias. Omnis eum dolorem quis.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Beton Hemd",
+ "description" => "Nesciunt eos qui consectetur sint et accusamus possimus. Alias quis quasi qui vel est corporis consequuntur. Aspernatur facilis est ullam quia in et.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Concrete Shirt",
+ "description" => "Saepe autem quia dicta nemo suscipit. Repellat labore sit quas quo. Itaque qui vitae sunt quis quasi qui.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Genial Gummi Flasche",
+ "description" => "Laudantium hic in et nobis. Culpa illum tenetur aliquid iure adipisci exercitationem a. Perspiciatis vero ut accusamus minus incidunt numquam error.",
+ ],
+ "en" => [
+ "name" => "Awesome Rubber Bottle",
+ "description" => "Aut maxime sint similique quia. At maxime ea ab laudantium. Cum saepe odit sint eius earum est. Qui laudantium omnis est eligendi dolores ut.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Mittelm\u00e4\u00dfig Granit Wagen",
+ "description" => "Molestiae ut ut quo qui atque a placeat. Asperiores vel deserunt qui natus maxime. Esse ut hic autem et. Porro ducimus ducimus debitis et quo quam.",
+ ],
+ "en" => [
+ "name" => "Mediocre Granite Car",
+ "description" => "Deleniti ab saepe voluptatem rerum amet sed. Et dolores aut est enim. Ea eaque eum suscipit et eius exercitationem. Dicta sapiente et eaque labore. Soluta laboriosam magni veniam quia est.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Herrlich Leder Uhr",
+ "description" => "Voluptas assumenda ratione impedit optio dolorem ea rerum. Qui in quidem cum consequatur natus eos quis.",
+ ],
+ "en" => [
+ "name" => "Gorgeous Leather Clock",
+ "description" => "Cum sed in doloremque repellendus velit veniam accusantium fugiat. Aut ea est eos iusto sunt voluptate. Provident possimus ipsa alias earum velit dolor ipsam.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Synergistisch Stahl Lampe",
+ "description" => "Est maiores qui vel. Aut aut labore rerum qui architecto tempora. Consectetur rerum veritatis magnam in numquam quidem ex. Et et molestiae quaerat rerum.",
+ ],
+ "en" => [
+ "name" => "Synergistic Steel Lamp",
+ "description" => "Et molestiae unde quo aliquid officiis omnis est. Veritatis voluptatem corporis accusantium qui molestiae sunt deleniti. Fuga tenetur molestias facere est et. Repellendus et ad omnis sunt sequi.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Intelligent Stahl Teller",
+ "description" => "Eius perspiciatis quia ipsam eum deserunt. Doloribus et quas architecto quia. Aut blanditiis sed nulla nesciunt.",
+ ],
+ "en" => [
+ "name" => "Intelligent Steel Plate",
+ "description" => "Sunt et quia molestias aut impedit quisquam provident. Vel nisi id odio harum ducimus iusto autem. Veniam ut et tenetur cumque animi nisi accusantium.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Genial Die Seide Tastatur",
+ "description" => "Distinctio voluptatem amet enim accusamus possimus nihil atque. Aspernatur fugit ad excepturi perferendis corrupti nihil.",
+ ],
+ "en" => [
+ "name" => "Awesome Silk Keyboard",
+ "description" => "Fuga quo excepturi iure dolor et eum assumenda. Omnis eum odio non tempora autem consequatur. Sed cum ut praesentium ut. Id est dignissimos magnam in dolores blanditiis.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Bronze Lampe",
+ "description" => "Impedit quisquam cumque voluptatum velit id. At maxime ipsam repellendus doloribus dolorem. Sit fugit sequi quis. Et veritatis animi culpa voluptates. Quibusdam hic id nemo quia veritatis dolorem.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Bronze Lamp",
+ "description" => "Voluptatem sequi corrupti rerum nihil blanditiis repudiandae totam. Qui quia incidunt magni inventore voluptatem quisquam. Ipsam odio odio nemo fugiat tempora minus nisi.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Leicht Baumwolle Flasche",
+ "description" => "Velit et ea natus delectus dolore. Qui odio earum a at quisquam delectus. Autem excepturi magnam iusto rerum in. Voluptatem et ullam minus minus odit quos voluptas.",
+ ],
+ "en" => [
+ "name" => "Lightweight Cotton Bottle",
+ "description" => "Aut voluptatibus voluptatem deserunt praesentium molestiae eveniet. Ex sed asperiores non tempore nihil. Rerum aut eos numquam mollitia enim provident.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Glatt Leder Bank",
+ "description" => "Consequatur saepe eius id labore. Accusamus nihil in excepturi aperiam est rerum. Earum voluptatem non saepe et consequuntur non eveniet. Eum qui earum dolores voluptas cum.",
+ ],
+ "en" => [
+ "name" => "Sleek Leather Bench",
+ "description" => "Eum autem at cumque non. In nihil et vitae. Error sit fugiat impedit explicabo vero consequuntur quia. Numquam quos aut molestiae iure.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Mittelm\u00e4\u00dfig Leinen Mantel",
+ "description" => "Dignissimos magni adipisci cumque quia voluptatem ut. Pariatur consequatur labore aut omnis sit. Non dolorum ut officia qui.",
+ ],
+ "en" => [
+ "name" => "Mediocre Linen Coat",
+ "description" => "Facere velit aut eum vel dolor. Animi deleniti cum quia sit et voluptatem. Excepturi inventore quia voluptas voluptatem accusantium labore iusto. Quo fugit eaque sunt error qui sed.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Dauerhaft Eisen Hose",
+ "description" => "Accusamus quam sit sequi quo rerum ipsam. Ex enim molestiae dolores repudiandae quas dolor. Inventore odio ipsam quo quibusdam perferendis similique eos maiores.",
+ ],
+ "en" => [
+ "name" => "Durable Iron Pants",
+ "description" => "Autem quis laudantium odit sed repellat aut. Deleniti ratione itaque quaerat eum vel alias. Esse dicta odit facilis eius.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Herrlich Marmor Brieftasche",
+ "description" => "Delectus labore sit alias voluptas. Quo doloribus quod mollitia deleniti laboriosam. Culpa laudantium nulla accusamus id qui ut. A omnis voluptatem omnis qui.",
+ ],
+ "en" => [
+ "name" => "Gorgeous Marble Wallet",
+ "description" => "Neque dolores qui ut officiis explicabo voluptatum qui. Fugit tenetur id sapiente esse aut eligendi et facere. Sed quos quia molestiae odit.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Dauerhaft Aluminium Bank",
+ "description" => "Facere architecto ullam aut. Sapiente qui mollitia minus iure omnis impedit praesentium. Debitis ea vero est doloribus laboriosam ex tempora. Natus odio ipsam magni voluptas id voluptatibus.",
+ ],
+ "en" => [
+ "name" => "Durable Aluminum Bench",
+ "description" => "Aut perspiciatis occaecati dolores quia nostrum sint. Harum natus est saepe laboriosam accusamus dolorem.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Intelligent H\u00f6lzern Computer",
+ "description" => "Nobis modi aspernatur non id esse accusantium. Qui impedit delectus quia eum eligendi quas.",
+ ],
+ "en" => [
+ "name" => "Intelligent Wooden Computer",
+ "description" => "Ab sunt est voluptatibus veniam. Est possimus quia fugiat id perferendis repellat non soluta. Eaque sequi velit sint ipsum.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Dauerhaft Leder Computer",
+ "description" => "Earum laudantium voluptates culpa ut delectus est doloribus dolores. Ullam iure et iure impedit voluptate sit error.",
+ ],
+ "en" => [
+ "name" => "Durable Leather Computer",
+ "description" => "Corporis quibusdam autem necessitatibus dolorem unde totam cum temporibus. Ipsa quam qui et asperiores autem quam consequatur. Est eos dolores est laboriosam sit.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Ergonomisch Baumwolle Wagen",
+ "description" => "Consectetur labore est consectetur beatae cumque dignissimos. Velit tenetur error maiores et veniam. Quia impedit quasi doloribus quos omnis delectus sit quia.",
+ ],
+ "en" => [
+ "name" => "Ergonomic Cotton Car",
+ "description" => "Voluptatem quos eaque esse doloremque. Neque rerum eum mollitia nam. Quo facere vitae et odio molestiae.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Aluminium Uhr",
+ "description" => "Magnam natus non eos optio perspiciatis nisi. Nihil voluptates et iste eius vel possimus. Quasi fugit fugiat illum labore debitis. Quae possimus provident non recusandae sint.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Aluminum Clock",
+ "description" => "Beatae voluptatem quisquam aut omnis perspiciatis. Maiores ut et omnis et est. Nostrum dolorum molestias perspiciatis porro sit porro perspiciatis.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Enorm H\u00f6lzern Mantel",
+ "description" => "Temporibus consequuntur vero debitis omnis numquam est. Qui et blanditiis perferendis facere eaque sapiente voluptas. Sed iste tempora nulla minus ipsa.",
+ ],
+ "en" => [
+ "name" => "Enormous Wooden Coat",
+ "description" => "Cumque voluptas nemo voluptatem non ut repudiandae esse. Doloribus molestiae laudantium quidem voluptas. Et numquam suscipit aliquid nihil enim corrupti.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Mittelm\u00e4\u00dfig Marmor Uhr",
+ "description" => "Culpa et dolor qui recusandae sint deserunt dolorem. Mollitia qui nisi dolores earum pariatur quo. Sint eligendi accusamus eius in.",
+ ],
+ "en" => [
+ "name" => "Mediocre Marble Watch",
+ "description" => "Sed odio autem inventore sint. Est temporibus minima odit et nulla ipsam et molestias. Quas ut et dolore et officiis ullam.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Glatt Papier Wagen",
+ "description" => "Hic perferendis et sunt consequatur. Corrupti est quo eum sunt aut aut. Quia provident doloribus aliquid vero quod adipisci molestias minima.",
+ ],
+ "en" => [
+ "name" => "Sleek Paper Car",
+ "description" => "Quis rerum eligendi dolor neque. A commodi illum consequuntur. Repellendus aliquam molestias et expedita quia.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Unglaublich Aluminium Hut",
+ "description" => "Incidunt laudantium reiciendis et consequuntur officiis. Iste sint consequatur rem qui qui officia. Voluptas et dolorem quia omnis est officiis voluptates.",
+ ],
+ "en" => [
+ "name" => "Incredible Aluminum Hat",
+ "description" => "Ut itaque alias aspernatur aliquam. Dolor ullam porro magni doloribus corporis illo molestiae. Aliquam est possimus nihil eos reiciendis ex. Laborum harum tempora et autem possimus aut eum id.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Ergonomisch Eisen Lampe",
+ "description" => "Et qui soluta et velit et iste. Sapiente ut pariatur neque tempore libero placeat. Adipisci dolor consequatur architecto ut in optio. Voluptatem numquam id suscipit eum consequuntur voluptatem.",
+ ],
+ "en" => [
+ "name" => "Ergonomic Iron Lamp",
+ "description" => "Ipsum consectetur aut perspiciatis eum. Nulla at id eveniet ipsa sapiente. Dicta temporibus enim in fugit quia qui molestias. Id aut rem omnis similique at est fugiat fuga.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Intelligent H\u00f6lzern Handschuhe",
+ "description" => "Veritatis quia unde ab omnis est dolorem qui beatae. Expedita sit qui eveniet aliquid. Officiis cumque similique nulla perspiciatis. Quaerat exercitationem rerum cumque consequuntur et quasi.",
+ ],
+ "en" => [
+ "name" => "Intelligent Wooden Gloves",
+ "description" => "Cumque ex voluptatem fugit esse. Et illo enim odit. Minima sit molestiae autem omnis soluta. Commodi vitae porro dolor nemo.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Klein Papier Hemd",
+ "description" => "Ratione quia eum cum esse non et. Asperiores ratione pariatur adipisci in laudantium. Quos est quia dicta velit soluta quidem. Recusandae qui nisi in deserunt non.",
+ ],
+ "en" => [
+ "name" => "Small Paper Shirt",
+ "description" => "Esse nemo maiores ea deserunt ut quasi. Ut similique voluptatum sit accusamus. Reiciendis sint hic ut consequatur dolorem. Voluptates tempore placeat optio quia soluta expedita repellat.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Genial Gummi Uhr",
+ "description" => "Omnis blanditiis itaque ipsa ut. Eum rerum magni facere non laudantium recusandae dolorem. Ipsa illo voluptatem quis.",
+ ],
+ "en" => [
+ "name" => "Awesome Rubber Watch",
+ "description" => "Sint voluptatem accusamus inventore repellendus voluptatem nam. Aspernatur sit veritatis beatae et. Praesentium perspiciatis sunt quia eum sed nesciunt. Eaque beatae quibusdam sit natus.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Synergistisch Bronze Flasche",
+ "description" => "Tempora atque sint ipsa vero et quidem quis. Quia asperiores veritatis optio. Ea est sed quia placeat culpa labore doloribus.",
+ ],
+ "en" => [
+ "name" => "Synergistic Bronze Bottle",
+ "description" => "Et repellat eveniet fuga veniam. Similique magnam quod unde velit perspiciatis. Aspernatur ea iure aut quas id velit. Atque eaque consectetur et non aliquid repellat sunt.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Fantastisch Baumwolle Messer",
+ "description" => "Pariatur nesciunt sint voluptatem. Itaque non cumque voluptas ea rerum quibusdam vel. Quo dolor rem nobis cum. Blanditiis temporibus ad eos quasi.",
+ ],
+ "en" => [
+ "name" => "Fantastic Cotton Knife",
+ "description" => "Praesentium sunt qui nihil laboriosam rerum. Quis et nemo dolor ipsa. Sapiente quasi aut provident voluptas qui ipsam quae ut. Quo ducimus est dolorum ratione eos.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Dauerhaft Aluminium Stuhl",
+ "description" => "Ea sequi tenetur aut quasi necessitatibus nemo. Qui sequi ut ducimus officiis quae. Eos sit accusamus modi eligendi id ut id sint.",
+ ],
+ "en" => [
+ "name" => "Durable Aluminum Chair",
+ "description" => "Quibusdam distinctio exercitationem nobis corrupti et eius. Rem commodi enim qui commodi. Laboriosam quis vel dolorem adipisci. Rerum incidunt earum omnis quia. Laudantium in necessitatibus illum.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Dauerhaft Kupfer Computer",
+ "description" => "Perspiciatis rerum aut eos quibusdam distinctio aut. Corrupti fugiat animi a eos non quia quisquam. Dolorem consequuntur et sit ut.",
+ ],
+ "en" => [
+ "name" => "Durable Copper Computer",
+ "description" => "Quia ut nihil ipsum quo sint vel. Nemo nemo sit illum eum accusamus molestias dolor autem.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Leicht Stahl Computer",
+ "description" => "Tempore expedita beatae at adipisci. Quam qui aut blanditiis iure exercitationem et.",
+ ],
+ "en" => [
+ "name" => "Lightweight Steel Computer",
+ "description" => "Mollitia tenetur iure error soluta adipisci vitae praesentium. Iure minus veritatis sed doloremque ut maiores necessitatibus. Quia non id possimus eum reprehenderit.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Genial Marmor Uhr",
+ "description" => "Deserunt a molestiae hic itaque est cumque. Iusto aspernatur atque laborum doloribus. Rerum repudiandae quidem sit et blanditiis odio velit.",
+ ],
+ "en" => [
+ "name" => "Awesome Marble Clock",
+ "description" => "Et esse dolores aliquid suscipit autem. Repudiandae laborum sapiente odio excepturi voluptatem temporibus. Quia vel sed quia dolorem. Vel ut ut reprehenderit accusamus dolorum ducimus numquam.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Leinen Brieftasche",
+ "description" => "Tenetur dolor est iusto voluptatem. Praesentium explicabo occaecati asperiores et. Eligendi aperiam qui sapiente corporis quia. Velit aut dolore repellat officia ipsum.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Linen Wallet",
+ "description" => "Voluptatem rem et sunt dicta esse. Dolorem reprehenderit iusto velit vel suscipit deserunt aut. Neque eum beatae assumenda. Labore omnis vero sed exercitationem in.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Unglaublich Leinen Schuhe",
+ "description" => "Vel consequuntur dolor laborum non. Et alias architecto ut iure repellat laudantium dolorum. Quo consequuntur eos corporis vel. Saepe dolor minus nesciunt. Ut ducimus fugit a.",
+ ],
+ "en" => [
+ "name" => "Incredible Linen Shoes",
+ "description" => "Quidem tenetur ullam rerum quia et totam. Dolorum sed ut sit ex molestiae ut sit molestiae. Repudiandae velit illo dicta fugit vel necessitatibus.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Schwerlast H\u00f6lzern Mantel",
+ "description" => "Nostrum aperiam adipisci debitis ut in error. Dolore nulla sunt sint dolor modi. Atque in facilis mollitia. Mollitia praesentium sit ea.",
+ ],
+ "en" => [
+ "name" => "Heavy Duty Wooden Coat",
+ "description" => "Sed non voluptatem alias vitae. Voluptatibus corrupti voluptate perferendis iure ut voluptatem aut iusto. Rerum quia deleniti fugiat in vero.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Klein Papier Hose",
+ "description" => "Ut pariatur et voluptatem fugit. Vitae rerum ut sapiente dolorem. Quaerat ullam libero est. Qui quidem vel et totam. Et distinctio autem perferendis.",
+ ],
+ "en" => [
+ "name" => "Small Paper Pants",
+ "description" => "Ut officiis et voluptas similique. Eligendi modi expedita quis corrupti. Nemo itaque voluptas possimus nesciunt quia. Et nihil animi quo enim velit aut nemo.",
+ ],
+ ],
+ [
+ "de" => [
+ "name" => "Aerodynamisch Die Seide Brieftasche",
+ "description" => "Unde perferendis aperiam nihil. Necessitatibus perferendis nihil ut quo voluptatem. A laborum sed neque. Corrupti blanditiis architecto ratione numquam aut dolorem laudantium quo.",
+ ],
+ "en" => [
+ "name" => "Aerodynamic Silk Wallet",
+ "description" => "Sit eligendi totam sunt laudantium libero consectetur. Et error et veniam ea culpa provident pariatur.",
+ ],
+ ],
+ ];
+
public function getVersion(): string
{
return '2.0';
@@ -49,10 +552,14 @@ public function getDependencies(): array
protected function createProduct(string $parentPath): ProductInterface
{
+ $index = array_rand(static::$names);
+ $name = static::$names[$index];
+
+ unset(static::$names[$index]);
+
$faker = Factory::create();
$faker->addProvider(new Lorem($faker));
$faker->addProvider(new Barcode($faker));
- $faker->addProvider(new Commerce($faker));
$decimalFactor = $this->container->getParameter('coreshop.currency.decimal_factor');
@@ -68,16 +575,22 @@ protected function createProduct(string $parentPath): ProductInterface
/**
* @var CategoryInterface $usedCategory
*/
- $usedCategory = $categories[rand(0, count($categories) - 1)];
- $folder = \Pimcore\Model\Asset\Service::createFolderByPath(sprintf('/demo/%s/%s', $parentPath, Service::getValidKey($usedCategory->getName(), 'asset')));
+ $usedCategory = $categories[random_int(0, count($categories) - 1)];
+ $folder = \Pimcore\Model\Asset\Service::createFolderByPath(sprintf('/demo/%s/%s', $parentPath,
+ Service::getValidKey($usedCategory->getName(), 'asset')));
$images = [];
for ($j = 0; $j < 3; $j++) {
- $imagePath = $kernel->locateResource(sprintf('@CoreShopCoreBundle/Resources/fixtures/image%s.jpeg', rand(1, 3)));
+ $imagePath = $kernel->locateResource(
+ sprintf(
+ '@CoreShopCoreBundle/Resources/fixtures/image%s.jpeg',
+ random_int(1, 3)
+ )
+ );
$fileName = sprintf('image_%s.jpg', uniqid());
- $fullPath = $folder->getFullPath() . '/' . $fileName;
+ $fullPath = $folder->getFullPath().'/'.$fileName;
$existingImage = Asset::getByPath($fullPath);
@@ -99,10 +612,13 @@ protected function createProduct(string $parentPath): ProductInterface
* @var ProductInterface $product
*/
$product = $this->container->get('coreshop.factory.product')->createNew();
- $product->setName($faker->productName);
+ foreach (Tool::getValidLanguages() as $language) {
+ $product->setName($name[$language]['name'] ?? $name['en']['name'], $language);
+
+ $product->setShortDescription($name[$language]['description'] ?? $name['en']['description'], $language);
+ $product->setDescription(implode('
', $faker->paragraphs(3)), $language);
+ }
$product->setSku($faker->ean13);
- $product->setShortDescription($faker->text());
- $product->setDescription(implode('
', $faker->paragraphs(3)));
$product->setEan($faker->ean13);
$product->setActive(true);
$product->setCategories([$usedCategory]);
@@ -110,7 +626,7 @@ protected function createProduct(string $parentPath): ProductInterface
// $product->setWholesalePrice((int)($faker->randomFloat(2, 100, 200) * $decimalFactor));
foreach ($stores as $store) {
- $product->setStoreValuesOfType('price', (int) ($faker->randomFloat(2, 200, 400) * $decimalFactor), $store);
+ $product->setStoreValuesOfType('price', (int)($faker->randomFloat(2, 200, 400) * $decimalFactor), $store);
}
$product->setTaxRule($this->getReference('taxRule'));
@@ -120,7 +636,8 @@ protected function createProduct(string $parentPath): ProductInterface
$product->setWeight($faker->numberBetween(5, 10));
$product->setImages($images);
$product->setStores([$defaultStore]);
- $product->setParent($this->container->get(ObjectServiceInterface::class)->createFolderByPath(sprintf('/demo/%s/%s', $parentPath, Service::getValidKey($usedCategory->getName(), 'object'))));
+ $product->setParent($this->container->get(ObjectServiceInterface::class)->createFolderByPath(sprintf('/demo/%s/%s',
+ $parentPath, Service::getValidKey($usedCategory->getName(), 'object'))));
$product->setPublished(true);
$product->setKey($product->getName());
$product->setKey(Service::getUniqueKey($product));
diff --git a/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/CategoryFixture.php b/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/CategoryFixture.php
index 2d8b6ce054..ff2cecd48d 100644
--- a/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/CategoryFixture.php
+++ b/src/CoreShop/Bundle/CoreBundle/Fixtures/Data/Demo/CategoryFixture.php
@@ -14,14 +14,13 @@
namespace CoreShop\Bundle\CoreBundle\Fixtures\Data\Demo;
-use CoreShop\Bundle\CoreBundle\Faker\Commerce;
use CoreShop\Bundle\FixtureBundle\Fixture\VersionedFixtureInterface;
use CoreShop\Component\Core\Model\CategoryInterface;
use CoreShop\Component\Pimcore\DataObject\ObjectServiceInterface;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;
-use Faker\Factory;
use Pimcore\Model\DataObject\Service;
+use Pimcore\Tool;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -41,17 +40,42 @@ public function setContainer(ContainerInterface $container = null): void
public function load(ObjectManager $manager): void
{
+ $names = [
+ [
+ 'de' => 'Bücher',
+ 'en' => 'Books',
+ ],
+ [
+ 'de' => 'Computer',
+ 'en' => 'Computer',
+ ],
+ [
+ 'de' => 'Filme',
+ 'en' => 'Movies',
+ ],
+ [
+ 'de' => 'Kleidung',
+ 'en' => 'Clothing',
+ ],
+ [
+ 'de' => 'Schuhe',
+ 'en' => 'Shoes',
+ ],
+ ];
+
if (!count($this->container->get('coreshop.repository.category')->findAll())) {
$categoriesCount = 5;
- $faker = Factory::create();
- $faker->addProvider(new Commerce($faker));
for ($i = 0; $i < $categoriesCount; $i++) {
/**
* @var CategoryInterface $category
*/
$category = $this->container->get('coreshop.factory.category')->createNew();
- $category->setName($faker->department);
+
+ foreach (Tool::getValidLanguages() as $language) {
+ $category->setName($names[$i][$language] ?? $names[$i]['en'], $language);
+ }
+
$category->setParent($this->container->get(ObjectServiceInterface::class)->createFolderByPath('/demo/categories'));
$category->setStores([$this->container->get('coreshop.repository.store')->findStandard()->getId()]);
$category->setPublished(true);
diff --git a/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopCategory.json b/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopCategory.json
index 514bf0f253..74e02a59b9 100644
--- a/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopCategory.json
+++ b/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopCategory.json
@@ -7,7 +7,7 @@
"allowVariants": false,
"showVariants": false,
"generateTypeDeclarations": true,
- "linkGeneratorReference": "@coreshop.object.link_generator.category",
+ "linkGeneratorReference": "@CoreShop\\Component\\Pimcore\\Slug\\SluggableLinkGenerator",
"layoutDefinitions": {
"fieldtype": "panel",
"labelWidth": 100,
@@ -96,6 +96,27 @@
"invisible": false,
"visibleGridView": false,
"visibleSearch": false
+ },
+ {
+ "fieldtype": "urlSlug",
+ "width": "",
+ "domainLabelWidth": null,
+ "action": "CoreShop\\Bundle\\FrontendBundle\\Controller\\CategoryController:detailSlugAction",
+ "availableSites": [],
+ "name": "slug",
+ "title": "coreshop.category.slug",
+ "tooltip": "",
+ "mandatory": false,
+ "noteditable": false,
+ "index": false,
+ "locked": false,
+ "style": "",
+ "permissions": null,
+ "datatype": "data",
+ "relationType": false,
+ "invisible": false,
+ "visibleGridView": false,
+ "visibleSearch": false
}
],
"name": "localizedfields",
diff --git a/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopProduct.json b/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopProduct.json
index 85915d27b3..7af8cb7179 100644
--- a/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopProduct.json
+++ b/src/CoreShop/Bundle/CoreBundle/Resources/install/pimcore/classes/CoreShopProductBundle/CoreShopProduct.json
@@ -7,7 +7,7 @@
"allowVariants": false,
"showVariants": false,
"generateTypeDeclarations": true,
- "linkGeneratorReference": "@coreshop.object.link_generator.product",
+ "linkGeneratorReference": "@CoreShop\\Component\\Pimcore\\Slug\\SluggableLinkGenerator",
"layoutDefinitions": {
"fieldtype": "panel",
"labelWidth": 100,
@@ -110,6 +110,27 @@
"invisible": false,
"visibleGridView": true,
"visibleSearch": true
+ },
+ {
+ "fieldtype": "urlSlug",
+ "width": "",
+ "domainLabelWidth": null,
+ "action": "CoreShop\\Bundle\\FrontendBundle\\Controller\\ProductController:detailSlugAction",
+ "availableSites": [],
+ "name": "slug",
+ "title": "coreshop.product.slug",
+ "tooltip": "",
+ "mandatory": false,
+ "noteditable": false,
+ "index": false,
+ "locked": false,
+ "style": "",
+ "permissions": null,
+ "datatype": "data",
+ "relationType": false,
+ "invisible": false,
+ "visibleGridView": false,
+ "visibleSearch": false
}
],
"name": "localizedfields",
diff --git a/src/CoreShop/Bundle/FrontendBundle/Controller/CategoryController.php b/src/CoreShop/Bundle/FrontendBundle/Controller/CategoryController.php
index f914ccd890..036cf68ece 100644
--- a/src/CoreShop/Bundle/FrontendBundle/Controller/CategoryController.php
+++ b/src/CoreShop/Bundle/FrontendBundle/Controller/CategoryController.php
@@ -29,6 +29,7 @@
use CoreShop\Component\Tracking\Tracker\TrackerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\Http\RequestHelper;
+use Pimcore\Model\DataObject\Data\UrlSlug;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -68,7 +69,23 @@ public function menuLeftAction(Request $request): Response
]);
}
+ public function detailSlugAction(Request $request, CategoryInterface $object, UrlSlug $urlSlug)
+ {
+ return $this->detail($request, $object);
+ }
+
public function indexAction(Request $request): Response
+ {
+ $category = $this->getRepository()->findOneBy([$this->repositoryIdentifier => $request->get($this->requestIdentifier), 'pimcore_unpublished' => true]);
+
+ if (!$category instanceof CategoryInterface) {
+ throw new NotFoundHttpException(sprintf(sprintf('category with identifier "%s" (%s) not found', $this->repositoryIdentifier, $request->get($this->requestIdentifier))));
+ }
+
+ return $this->detail($request, $category);
+ }
+
+ public function detail(Request $request, CategoryInterface $category): Response
{
$listModeDefault = $this->getConfigurationService()->getForStore('system.category.list.mode');
$gridPerPageAllowed = $this->getConfigurationService()->getForStore('system.category.grid.per_page');
@@ -85,28 +102,8 @@ public function indexAction(Request $request): Response
$allowedPerPage = $type === 'list' ? $listPerPageAllowed : $gridPerPageAllowed;
$perPage = $request->get('perPage', $defaultPerPage);
- $isFrontendRequestByAdmin = false;
- $category = $this->getRepository()->findOneBy([$this->repositoryIdentifier => $request->get($this->requestIdentifier), 'pimcore_unpublished' => true]);
-
- if (!$category instanceof CategoryInterface) {
- throw new NotFoundHttpException(sprintf(sprintf('category with identifier "%s" (%s) not found', $this->repositoryIdentifier, $request->get($this->requestIdentifier))));
- }
- if ($this->get(RequestHelper::class)->isFrontendRequestByAdmin($request)) {
- $isFrontendRequestByAdmin = true;
- }
-
- if ($isFrontendRequestByAdmin === false && !$category->isPublished()) {
- throw new NotFoundHttpException('category not found');
- }
-
- if (!in_array($this->getContext()->getStore()->getId(), array_values($category->getStores()))) {
- throw new NotFoundHttpException(sprintf(sprintf('store (id %s) not available in category', $this->getContext()->getStore()->getId())));
- }
-
- if (!in_array($perPage, $allowedPerPage)) {
- $perPage = $defaultPerPage;
- }
+ $this->validateCategory($request, $category);
$viewParameters = [];
@@ -193,6 +190,23 @@ public function indexAction(Request $request): Response
return $this->render($this->templateConfigurator->findTemplate('Category/index.html'), $viewParameters);
}
+ protected function validateCategory(Request $request, CategoryInterface $category)
+ {
+ $isFrontendRequestByAdmin = false;
+
+ if ($this->get(RequestHelper::class)->isFrontendRequestByAdmin($request)) {
+ $isFrontendRequestByAdmin = true;
+ }
+
+ if ($isFrontendRequestByAdmin === false && !$category->isPublished()) {
+ throw new NotFoundHttpException('category not found');
+ }
+
+ if (!in_array($this->getContext()->getStore()->getId(), array_values($category->getStores()))) {
+ throw new NotFoundHttpException(sprintf(sprintf('store (id %s) not available in category', $this->getContext()->getStore()->getId())));
+ }
+ }
+
protected function parseSorting(string $sortString): array
{
$sort = [
diff --git a/src/CoreShop/Bundle/FrontendBundle/Controller/ProductController.php b/src/CoreShop/Bundle/FrontendBundle/Controller/ProductController.php
index 83df0493f0..191e14bd77 100644
--- a/src/CoreShop/Bundle/FrontendBundle/Controller/ProductController.php
+++ b/src/CoreShop/Bundle/FrontendBundle/Controller/ProductController.php
@@ -15,22 +15,18 @@
namespace CoreShop\Bundle\FrontendBundle\Controller;
use CoreShop\Component\Core\Model\ProductInterface;
+use CoreShop\Component\Order\Model\PurchasableInterface;
use CoreShop\Component\SEO\SEOPresentationInterface;
use CoreShop\Component\Store\Context\StoreContextInterface;
use CoreShop\Component\Tracking\Tracker\TrackerInterface;
use Pimcore\Http\RequestHelper;
-use Pimcore\Model\DataObject;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ProductController extends FrontendController
{
- /**
- * @param Request $request
- *
- * @return \Symfony\Component\HttpFoundation\Response
- */
- public function latestAction(Request $request)
+ public function latestAction(Request $request): Response
{
$productRepository = $this->get('coreshop.repository.product');
@@ -39,21 +35,40 @@ public function latestAction(Request $request)
]);
}
- /**
- * @param Request $request
- *
- * @return \Symfony\Component\HttpFoundation\Response
- */
- public function detailAction(Request $request)
+ public function detailSlugAction(Request $request, ProductInterface $object)
{
- $product = $this->getProductByRequest($request);
+ $this->validateProduct($request, $object);
- $isFrontendRequestByAdmin = false;
+ $this->get(SEOPresentationInterface::class)->updateSeoMetadata($object);
+ $this->get(TrackerInterface::class)->trackProduct($object);
+
+ return $this->render($this->templateConfigurator->findTemplate('Product/detail.html'), [
+ 'product' => $object,
+ ]);
+ }
+
+ public function detailAction(Request $request): Response
+ {
+ $product = $this->getProductByRequest($request);
if (!$product instanceof ProductInterface) {
throw new NotFoundHttpException('product not found');
}
+ $this->validateProduct($request, $product);
+
+ $this->get(SEOPresentationInterface::class)->updateSeoMetadata($product);
+ $this->get(TrackerInterface::class)->trackProduct($product);
+
+ return $this->render($this->templateConfigurator->findTemplate('Product/detail.html'), [
+ 'product' => $product,
+ ]);
+ }
+
+ protected function validateProduct(Request $request, ProductInterface $product): void
+ {
+ $isFrontendRequestByAdmin = false;
+
if ($this->get(RequestHelper::class)->isFrontendRequestByAdmin($request)) {
$isFrontendRequestByAdmin = true;
}
@@ -65,21 +80,9 @@ public function detailAction(Request $request)
if (!in_array($this->get(StoreContextInterface::class)->getStore()->getId(), $product->getStores())) {
throw new NotFoundHttpException('product not found');
}
-
- $this->get(SEOPresentationInterface::class)->updateSeoMetadata($product);
- $this->get(TrackerInterface::class)->trackProduct($product);
-
- return $this->render($this->templateConfigurator->findTemplate('Product/detail.html'), [
- 'product' => $product,
- ]);
}
- /**
- * @param Request $request
- *
- * @return DataObject\Concrete
- */
- protected function getProductByRequest(Request $request)
+ protected function getProductByRequest(Request $request): ?PurchasableInterface
{
return $this->get('coreshop.repository.stack.purchasable')->find($request->get('product'));
}
diff --git a/src/CoreShop/Bundle/FrontendBundle/Resources/install/pimcore/staticroutes.yml b/src/CoreShop/Bundle/FrontendBundle/Resources/install/pimcore/staticroutes.yml
index 5ec2eb4adf..2d04713b5e 100644
--- a/src/CoreShop/Bundle/FrontendBundle/Resources/install/pimcore/staticroutes.yml
+++ b/src/CoreShop/Bundle/FrontendBundle/Resources/install/pimcore/staticroutes.yml
@@ -6,20 +6,6 @@ routes:
variables: _locale
priority: 1
- coreshop_category_list:
- pattern: '/(\w+)\/shop\/(.*?)\~c([0-9]+)$/'
- reverse: '/%_locale/shop/%name~c%category'
- controller: 'CoreShop\Bundle\FrontendBundle\Controller\CategoryController:indexAction'
- variables: _locale,name,category
- priority: 2
-
- coreshop_product_detail:
- pattern: '/(\w+)\/shop\/(.*?)\~p([0-9]+)$/'
- reverse: '/%_locale/shop/%name~p%product'
- controller: 'CoreShop\Bundle\FrontendBundle\Controller\ProductController:detailAction'
- variables: _locale,name,product
- priority: 2
-
coreshop_cart_summary:
pattern: '/(\w+)\/shop\/cart$/'
reverse: '/%_locale/shop/cart'
diff --git a/src/CoreShop/Bundle/PimcoreBundle/EventListener/SluggableListener.php b/src/CoreShop/Bundle/PimcoreBundle/EventListener/SluggableListener.php
new file mode 100644
index 0000000000..0fa28eec73
--- /dev/null
+++ b/src/CoreShop/Bundle/PimcoreBundle/EventListener/SluggableListener.php
@@ -0,0 +1,102 @@
+slugger = $slugger;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return [
+ DataObjectEvents::PRE_UPDATE => 'preUpdate',
+ DataObjectEvents::PRE_ADD => 'preUpdate',
+ ];
+ }
+
+ public function preUpdate(DataObjectEvent $dataObjectEvent)
+ {
+ $object = $dataObjectEvent->getObject();
+
+ if (!$object instanceof SluggableInterface) {
+ return;
+ }
+
+ $sites = new Site\Listing();
+
+ foreach (Tool::getValidLanguages() as $language) {
+ $newSlugs = [];
+ $actualSlugs = [];
+ $name = $object->getNameForSlug($language);
+
+ if (!$name) {
+ continue;
+ }
+
+ $slug = sprintf(
+ '/%s/%s',
+ $language,
+ strtolower($this->slugger->slug($name, '-', $language)->toString())
+ );
+
+ $newSlugs[] = new UrlSlug($slug, 0);
+
+ foreach ($sites->getSites() as $site) {
+ $newSlugs[] = new UrlSlug($slug, $site->getId());
+ }
+
+ $existingSlugs = $object->getSlug($language);
+
+ foreach ($newSlugs as $newSlug) {
+ $found = false;
+
+ foreach ($existingSlugs as $existingSlug) {
+ if ($existingSlug->getSiteId() === $newSlug->getSiteId()) {
+ if ($existingSlug->getSlug() === $newSlug->getSlug()) {
+ $actualSlugs[] = $existingSlug;
+ }
+ else {
+ $newSlug->setPreviousSlug($existingSlug->getSlug());
+ $actualSlugs[] = $newSlug;
+
+ }
+ $found = true;
+ break;
+ }
+ }
+
+ if (!$found) {
+ $actualSlugs[] = $newSlug;
+ }
+ }
+
+ $object->setSlug($actualSlugs, $language);
+ }
+ }
+}
diff --git a/src/CoreShop/Bundle/PimcoreBundle/Resources/config/services.yml b/src/CoreShop/Bundle/PimcoreBundle/Resources/config/services.yml
index f4314f87ca..81e11902ad 100755
--- a/src/CoreShop/Bundle/PimcoreBundle/Resources/config/services.yml
+++ b/src/CoreShop/Bundle/PimcoreBundle/Resources/config/services.yml
@@ -70,3 +70,15 @@ services:
- '%coreshop.all.pimcore.admin.editmode_css%'
tags:
- { name: kernel.event_subscriber }
+
+ CoreShop\Bundle\PimcoreBundle\EventListener\SluggableListener:
+ arguments:
+ - '@Symfony\Component\String\Slugger\SluggerInterface'
+ tags:
+ - { name: kernel.event_subscriber }
+
+ CoreShop\Component\Pimcore\Slug\SluggableLinkGenerator:
+ public: true
+ arguments:
+ - '@Pimcore\Http\Request\Resolver\SiteResolver'
+ - '@Symfony\Component\HttpFoundation\RequestStack'
diff --git a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/admin-translations.yml b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/admin-translations.yml
index f7bc4749af..589aae259e 100644
--- a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/admin-translations.yml
+++ b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/admin-translations.yml
@@ -158,3 +158,13 @@ translations:
languages:
en: 'Depth'
de: 'Tiefe'
+
+ coreshop.product.slug:
+ languages:
+ en: 'Slug'
+ de: 'Slug'
+
+ coreshop.category.slug:
+ languages:
+ en: 'Slug'
+ de: 'Slug'
diff --git a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopCategory.json b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopCategory.json
index d555ec8164..6d51ae0ab1 100644
--- a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopCategory.json
+++ b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopCategory.json
@@ -7,6 +7,7 @@
"allowVariants": false,
"showVariants": false,
"generateTypeDeclarations": true,
+ "linkGeneratorReference": "@CoreShop\\Component\\Pimcore\\Slug\\SluggableLinkGenerator",
"layoutDefinitions": {
"fieldtype": "panel",
"labelWidth": 100,
@@ -80,6 +81,27 @@
"invisible": false,
"visibleGridView": false,
"visibleSearch": false
+ },
+ {
+ "fieldtype": "urlSlug",
+ "width": "",
+ "domainLabelWidth": null,
+ "action": "CoreShop\\Bundle\\FrontendBundle\\Controller\\CategoryController:detailSlugAction",
+ "availableSites": [],
+ "name": "slug",
+ "title": "coreshop.category.slug",
+ "tooltip": "",
+ "mandatory": false,
+ "noteditable": false,
+ "index": false,
+ "locked": false,
+ "style": "",
+ "permissions": null,
+ "datatype": "data",
+ "relationType": false,
+ "invisible": false,
+ "visibleGridView": false,
+ "visibleSearch": false
}
],
"name": "localizedfields",
@@ -133,8 +155,6 @@
"icon": null,
"previewUrl": null,
"group": "CoreShop",
- "generateTypeDeclarations": true,
-
"propertyVisibility": {
"grid": {
"id": true,
diff --git a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopProduct.json b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopProduct.json
index 65aed511dc..6c70e3c302 100644
--- a/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopProduct.json
+++ b/src/CoreShop/Bundle/ProductBundle/Resources/install/pimcore/classes/CoreShopProduct.json
@@ -7,6 +7,7 @@
"allowVariants": false,
"showVariants": false,
"generateTypeDeclarations": true,
+ "linkGeneratorReference": "@CoreShop\\Component\\Pimcore\\Slug\\SluggableLinkGenerator",
"layoutDefinitions": {
"fieldtype": "panel",
"labelWidth": 100,
@@ -109,6 +110,27 @@
"invisible": false,
"visibleGridView": false,
"visibleSearch": false
+ },
+ {
+ "fieldtype": "urlSlug",
+ "width": "",
+ "domainLabelWidth": null,
+ "action": "CoreShop\\Bundle\\FrontendBundle\\Controller\\ProductController:detailSlugAction",
+ "availableSites": [],
+ "name": "slug",
+ "title": "coreshop.product.slug",
+ "tooltip": "",
+ "mandatory": false,
+ "noteditable": false,
+ "index": false,
+ "locked": false,
+ "style": "",
+ "permissions": null,
+ "datatype": "data",
+ "relationType": false,
+ "invisible": false,
+ "visibleGridView": false,
+ "visibleSearch": false
}
],
"name": "localizedfields",
@@ -659,7 +681,6 @@
"icon": null,
"previewUrl": null,
"group": "CoreShop",
- "generateTypeDeclarations": true,
"propertyVisibility": {
"grid": {
diff --git a/src/CoreShop/Component/Pimcore/Slug/SluggableInterface.php b/src/CoreShop/Component/Pimcore/Slug/SluggableInterface.php
new file mode 100644
index 0000000000..40d72fdcd2
--- /dev/null
+++ b/src/CoreShop/Component/Pimcore/Slug/SluggableInterface.php
@@ -0,0 +1,32 @@
+siteResolver = $siteResolver;
+ $this->requestStack = $requestStack;
+ }
+
+ public function generate(Concrete $object, array $params = []): string
+ {
+ if (!$object instanceof SluggableInterface) {
+ throw new \InvalidArgumentException(sprintf('Object with Path "%s" must implement %s',
+ $object->getFullPath(), SluggableInterface::class));
+ }
+
+ $slugs = $object->getSlug($params['_locale'] ?? null);
+ $slug = null;
+ $site = $params['site'] ?? (
+ $this->requestStack->getMasterRequest() ?
+ $this->siteResolver->getSite($this->requestStack->getMasterRequest()) :
+ null
+ );
+
+ foreach ($slugs as $possibleSlug) {
+ if ($possibleSlug->getSiteId() === ($site ? $site->getId() : 0)) {
+ $slug = $possibleSlug;
+ break;
+ }
+ }
+
+ if (null === $slug) {
+ throw new \InvalidArgumentException(sprintf('No Valid Slug found for object "%s"', $object->getFullPath()));
+ }
+
+ return $slug->getSlug();
+ }
+}
diff --git a/src/CoreShop/Component/Product/Model/Category.php b/src/CoreShop/Component/Product/Model/Category.php
index 8a74c0cb28..019864c2e9 100644
--- a/src/CoreShop/Component/Product/Model/Category.php
+++ b/src/CoreShop/Component/Product/Model/Category.php
@@ -34,6 +34,11 @@ public function hasChildCategories(): bool
return count($this->getChildren()) > 0;
}
+ public function getNameForSlug($language = null): ?string
+ {
+ return $this->getName($language);
+ }
+
public function getHierarchy(): array
{
$hierarchy = [];
diff --git a/src/CoreShop/Component/Product/Model/CategoryInterface.php b/src/CoreShop/Component/Product/Model/CategoryInterface.php
index b09159f34e..32754590b7 100644
--- a/src/CoreShop/Component/Product/Model/CategoryInterface.php
+++ b/src/CoreShop/Component/Product/Model/CategoryInterface.php
@@ -14,9 +14,10 @@
namespace CoreShop\Component\Product\Model;
+use CoreShop\Component\Pimcore\Slug\SluggableInterface;
use CoreShop\Component\Resource\Pimcore\Model\PimcoreModelInterface;
-interface CategoryInterface extends PimcoreModelInterface
+interface CategoryInterface extends PimcoreModelInterface, SluggableInterface
{
public function getName($language = null): ?string;
diff --git a/src/CoreShop/Component/Product/Model/Product.php b/src/CoreShop/Component/Product/Model/Product.php
index 521b4fb698..caae883f28 100644
--- a/src/CoreShop/Component/Product/Model/Product.php
+++ b/src/CoreShop/Component/Product/Model/Product.php
@@ -45,4 +45,9 @@ public function hasAdditionalUnitDefinitions(): bool
{
return $this->hasUnitDefinitions() && $this->getUnitDefinitions()->getAdditionalUnitDefinitions()->count() > 0;
}
+
+ public function getNameForSlug($language = null): ?string
+ {
+ return $this->getName($language);
+ }
}
diff --git a/src/CoreShop/Component/Product/Model/ProductInterface.php b/src/CoreShop/Component/Product/Model/ProductInterface.php
index 9d5b392dd9..07a52c8fee 100644
--- a/src/CoreShop/Component/Product/Model/ProductInterface.php
+++ b/src/CoreShop/Component/Product/Model/ProductInterface.php
@@ -14,11 +14,12 @@
namespace CoreShop\Component\Product\Model;
+use CoreShop\Component\Pimcore\Slug\SluggableInterface;
use CoreShop\Component\Resource\Model\ToggleableInterface;
use CoreShop\Component\Resource\Pimcore\Model\PimcoreModelInterface;
use Pimcore\Model\Asset\Image;
-interface ProductInterface extends PimcoreModelInterface, ToggleableInterface
+interface ProductInterface extends PimcoreModelInterface, ToggleableInterface, SluggableInterface
{
public function getSku(): ?string;