set correct category url_path in multiple root categories environment

This commit is contained in:
MonaHartdegen 2020-01-06 15:37:55 +01:00
parent f4499b4728
commit c065631a58
9 changed files with 316 additions and 31 deletions

View File

@ -23,9 +23,8 @@ class AddStoredFunctionToGetUrlPathOfCategory extends Migration
BEGIN
DECLARE urlPath VARCHAR(255);
CREATE TEMPORARY TABLE IF NOT EXISTS root_categories AS (SELECT id FROM categories where parent_id IS NULL);
IF categoryId NOT IN (SELECT id FROM root_categories)
-- Category with id 1 is root by default
IF categoryId <> 1
THEN
SELECT
GROUP_CONCAT(parent_translations.slug SEPARATOR '/') INTO urlPath
@ -37,20 +36,14 @@ class AddStoredFunctionToGetUrlPathOfCategory extends Migration
node._lft >= parent._lft
AND node._rgt <= parent._rgt
AND node.id = categoryId
AND parent.id NOT IN (SELECT id FROM root_categories)
AND parent.id <> 1
AND parent_translations.locale = localeCode
GROUP BY
node.id;
IF urlPath IS NULL
THEN
SET urlPath = (
SELECT slug
FROM category_translations
WHERE
category_translations.category_id = categoryId
AND category_translations.locale = localeCode
);
THEN
SET urlPath = (SELECT slug FROM category_translations WHERE category_translations.category_id = categoryId);
END IF;
ELSE
SET urlPath = '';

View File

@ -63,9 +63,8 @@ SQL;
DECLARE parentUrlPath varchar(255);
DECLARE urlPath varchar(255);
CREATE TEMPORARY TABLE IF NOT EXISTS root_categories AS (SELECT id FROM categories where parent_id IS NULL);
IF NEW.category_id NOT IN (SELECT id FROM root_categories)
-- Category with id 1 is root by default
IF NEW.category_id <> 1
THEN
SELECT
@ -78,8 +77,7 @@ SQL;
node._lft >= parent._lft
AND node._rgt <= parent._rgt
AND node.id = (SELECT parent_id FROM categories WHERE id = NEW.category_id)
AND node.parent_id IS NOT NULL
AND parent.parent_id IS NOT NULL
AND parent.id <> 1
AND parent_translations.locale = NEW.locale
GROUP BY
node.id;

View File

@ -69,6 +69,7 @@ SQL;
WHERE category_id = NEW.id);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
IF EXISTS (
SELECT *
FROM category_translations
@ -78,29 +79,21 @@ SQL;
OPEN curs;
SET done = 0;
SET done = 0;
REPEAT
FETCH curs INTO localeCode;
FETCH curs INTO localeCode;
SELECT get_url_path_of_category(NEW.id, localeCode) INTO urlPath;
IF NEW.parent_id IS NULL
THEN
SET urlPath = '';
END IF;
UPDATE category_translations
SET url_path = urlPath
WHERE
category_translations.category_id = NEW.id
AND category_translations.locale = localeCode;
SET url_path = urlPath
WHERE category_translations.category_id = NEW.id;
UNTIL done END REPEAT;
CLOSE curs;
END IF;
SQL;
}
}

View File

@ -0,0 +1,111 @@
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Migrations\Migration;
class AlterTriggerCategoryTranslations extends Migration
{
private const TRIGGER_NAME_INSERT = 'trig_category_translations_insert';
private const TRIGGER_NAME_UPDATE = 'trig_category_translations_update';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$triggerBody = $this->getTriggerBody();
$insertTrigger = <<< SQL
CREATE TRIGGER %s
BEFORE INSERT ON category_translations
FOR EACH ROW
BEGIN
$triggerBody
END;
SQL;
$updateTrigger = <<< SQL
CREATE TRIGGER %s
BEFORE UPDATE ON category_translations
FOR EACH ROW
BEGIN
$triggerBody
END;
SQL;
$this->dropTriggers();
DB::unprepared(sprintf($insertTrigger, self::TRIGGER_NAME_INSERT));
DB::unprepared(sprintf($updateTrigger, self::TRIGGER_NAME_UPDATE));
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$this->dropTriggers();
}
/**
* Drop the triggers
*/
private function dropTriggers()
{
DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_INSERT));
DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_UPDATE));
}
/**
* Returns trigger body as string
*
* @return string
*/
private function getTriggerBody()
{
return <<<SQL
DECLARE parentUrlPath varchar(255);
DECLARE urlPath varchar(255);
IF NOT EXISTS (
SELECT id
FROM categories
WHERE
id = NEW.category_id
AND parent_id IS NULL
)
THEN
SELECT
GROUP_CONCAT(parent_translations.slug SEPARATOR '/') INTO parentUrlPath
FROM
categories AS node,
categories AS parent
JOIN category_translations AS parent_translations ON parent.id = parent_translations.category_id
WHERE
node._lft >= parent._lft
AND node._rgt <= parent._rgt
AND node.id = (SELECT parent_id FROM categories WHERE id = NEW.category_id)
AND node.parent_id IS NOT NULL
AND parent.parent_id IS NOT NULL
AND parent_translations.locale = NEW.locale
GROUP BY
node.id;
IF parentUrlPath IS NULL
THEN
SET urlPath = NEW.slug;
ELSE
SET urlPath = concat(parentUrlPath, '/', NEW.slug);
END IF;
SET NEW.url_path = urlPath;
END IF;
SQL;
}
}

View File

@ -0,0 +1,75 @@
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Migrations\Migration;
class AlterStoredFunctionUrlPathCategory extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$functionSQL = <<< SQL
DROP FUNCTION IF EXISTS `get_url_path_of_category`;
CREATE FUNCTION get_url_path_of_category(
categoryId INT,
localeCode VARCHAR(255)
)
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE urlPath VARCHAR(255);
IF NOT EXISTS (
SELECT id
FROM categories
WHERE
id = categoryId
AND parent_id IS NULL
)
THEN
SELECT
GROUP_CONCAT(parent_translations.slug SEPARATOR '/') INTO urlPath
FROM
categories AS node,
categories AS parent
JOIN category_translations AS parent_translations ON parent.id = parent_translations.category_id
WHERE
node._lft >= parent._lft
AND node._rgt <= parent._rgt
AND node.id = categoryId
AND node.parent_id IS NOT NULL
AND parent.parent_id IS NOT NULL
AND parent_translations.locale = localeCode
GROUP BY
node.id;
IF urlPath IS NULL
THEN
SET urlPath = (SELECT slug FROM category_translations WHERE category_translations.category_id = categoryId);
END IF;
ELSE
SET urlPath = '';
END IF;
RETURN urlPath;
END;
SQL;
DB::unprepared($functionSQL);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::unprepared('DROP FUNCTION IF EXISTS `get_url_path_of_category`;');
}
}

View File

@ -0,0 +1,114 @@
<?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AlterTriggerOnCategories extends Migration
{
private const TRIGGER_NAME_INSERT = 'trig_categories_insert';
private const TRIGGER_NAME_UPDATE = 'trig_categories_update';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$triggerBody = $this->getTriggerBody();
$insertTrigger = <<< SQL
CREATE TRIGGER %s
AFTER INSERT ON categories
FOR EACH ROW
BEGIN
$triggerBody
END;
SQL;
$updateTrigger = <<< SQL
CREATE TRIGGER %s
AFTER UPDATE ON categories
FOR EACH ROW
BEGIN
$triggerBody
END;
SQL;
$this->dropTriggers();
DB::unprepared(sprintf($insertTrigger, self::TRIGGER_NAME_INSERT));
DB::unprepared(sprintf($updateTrigger, self::TRIGGER_NAME_UPDATE));
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$this->dropTriggers();
}
private function dropTriggers()
{
DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_INSERT));
DB::unprepared(sprintf('DROP TRIGGER IF EXISTS %s;', self::TRIGGER_NAME_UPDATE));
}
/**
* Returns trigger body as string
*
* @return string
*/
private function getTriggerBody(): string
{
return <<< SQL
DECLARE urlPath VARCHAR(255);
DECLARE localeCode VARCHAR(255);
DECLARE done INT;
DECLARE curs CURSOR FOR (SELECT category_translations.locale
FROM category_translations
WHERE category_id = NEW.id);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
IF EXISTS (
SELECT *
FROM category_translations
WHERE category_id = NEW.id
)
THEN
OPEN curs;
SET done = 0;
REPEAT
FETCH curs INTO localeCode;
SELECT get_url_path_of_category(NEW.id, localeCode) INTO urlPath;
IF NEW.parent_id IS NULL
THEN
SET urlPath = '';
END IF;
UPDATE category_translations
SET url_path = urlPath
WHERE
category_translations.category_id = NEW.id
AND category_translations.locale = localeCode;
UNTIL done END REPEAT;
CLOSE curs;
END IF;
SQL;
}
}

View File

@ -122,6 +122,8 @@ class DatabaseLogicCest
])->first();
$root2Category->save();
$I->assertNull($root2Category->refresh()->parent_id);
$urlPathQueryResult = DB::selectOne($sqlStoredFunction, [
'category_id' => $root2Category->id,
'locale_code' => $this->localeEn->code,

View File

@ -179,7 +179,6 @@ class TriggerCest
'locale' => $this->localeDe->code,
'url_path' => strtolower($this->parentCategoryName) . '/' . strtolower($this->categoryName)
]);
//eval(\psy\sh()); // TODO REMOVE
$I->seeRecord(CategoryTranslation::class, [
'category_id' => $this->root2Category->id,
'name' => $this->root2CategoryName,

View File

@ -97,7 +97,7 @@ class CategoryCest
'locale_id' => $this->localeEn->id,
],
];
$this->grandChildCategory = $I->make(Category::class, $this->grandChildCategoryAttributes);
$this->grandChildCategory = $I->make(Category::class, $this->grandChildCategoryAttributes)->first();
$this->childCategory->prependNode($this->grandChildCategory);
$I->assertNotNull($this->grandChildCategory);