From e7c88e0db91173487e01e61e4ef39e2bb47d4da3 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 7 Jul 2025 09:34:09 -0400 Subject: [PATCH 1/5] docs: enhance `README.md` with database setup instructions and migration details for single and multiple trees. --- README.md | 131 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 3f3798e..bae4920 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,112 @@ composer require yii2-extensions/nested-sets-behavior 3. **Optimizes queries** using boundary values for efficient tree traversal. 4. **Supports transactions** to ensure data integrity during complex operations. +## Database setup + +The package includes migrations to create the necessary database tables for nested sets functionality. + +### Available migrations + +The package provides two migration files. + +1. **Single tree migration** (`m250707_103609_tree.php`) - for single tree per table. +2. **Multiple trees migration** (`m250707_104009_multiple_tree.php`) - for multiple independent trees. + +### Using package migrations + +#### Method 1: Run migrations directly from extension (Recommended) + +Configure your console application to include the extension migrations path. + +```php + [ + 'migrate' => [ + 'class' => MigrateController::class, + 'migrationPath' => [ + '@console/migrations', // Your app migrations + '@vendor/yii2-extensions/nested-sets-behavior/migrations', // Extension migrations + ], + ], + ], +]; +``` + +Then run migrations normally. + +```bash +# View available migrations (including extension migrations) +./yii migrate/history + +# Run all pending migrations +./yii migrate + +# Or run specific migrations +./yii migrate/up m250707_103609_tree +./yii migrate/up m250707_104009_multiple_tree +``` + +#### Method 2: Using migration path parameter + +Run migrations directly without configuration changes. + +```bash +# Run single tree migration +./yii migrate/up --migrationPath=@vendor/yii2-extensions/nested-sets-behavior/migrations + +# Run specific migration from extension +./yii migrate/up m250707_103609_tree --migrationPath=@vendor/yii2-extensions/nested-sets-behavior/migrations +``` + +### Migration details + +#### Single tree migration (`m250707_103609_tree.php`) + +Creates a `tree` table with the following structure: + +```sql +CREATE TABLE `tree` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` text NOT NULL, + `lft` int(11) NOT NULL, + `rgt` int(11) NOT NULL, + `depth` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `idx_tree_lft` (`lft`), + KEY `idx_tree_rgt` (`rgt`), + KEY `idx_tree_depth` (`depth`), + KEY `idx_tree_lft_rgt` (`lft`,`rgt`) +); +``` + +#### Multiple tree migration (`m250707_104009_multiple_tree.php`) + +Creates a `multiple_tree` table with the following structure: + +```sql +CREATE TABLE `multiple_tree` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tree` int(11) DEFAULT NULL, + `name` text NOT NULL, + `lft` int(11) NOT NULL, + `rgt` int(11) NOT NULL, + `depth` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `idx_multiple_tree_tree` (`tree`), + KEY `idx_multiple_tree_lft` (`lft`), + KEY `idx_multiple_tree_rgt` (`rgt`), + KEY `idx_multiple_tree_depth` (`depth`), + KEY `idx_multiple_tree_tree_lft_rgt` (`tree`,`lft`,`rgt`) +); +``` + ### Basic Configuration Add the behavior to your ActiveRecord model. @@ -111,31 +217,6 @@ class Category extends ActiveRecord } ``` -### Database schema - -Create the required database fields. - -```sql --- Single tree structure -CREATE TABLE category ( - id INT PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - lft INT NOT NULL, - rgt INT NOT NULL, - depth INT NOT NULL -); - --- Multiple trees structure -CREATE TABLE category ( - id INT PRIMARY KEY AUTO_INCREMENT, - tree INT, - name VARCHAR(255) NOT NULL, - lft INT NOT NULL, - rgt INT NOT NULL, - depth INT NOT NULL -); -``` - ### Basic Usage #### Creating and building trees From f7e9eaef4060bb241dcfa31022c71c34eb6849d7 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 7 Jul 2025 09:46:12 -0400 Subject: [PATCH 2/5] fix: update `name` column type to varchar(255) in `tree` and `multiple_tree` migrations; add `MySQL` table options. --- README.md | 4 ++-- migrations/m250707_103609_tree.php | 8 +++++++- migrations/m250707_104009_multiple_tree.php | 7 ++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bae4920..5410a75 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Creates a `tree` table with the following structure: ```sql CREATE TABLE `tree` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `name` text NOT NULL, + `name` varchar(255) NOT NULL, `lft` int(11) NOT NULL, `rgt` int(11) NOT NULL, `depth` int(11) NOT NULL, @@ -157,7 +157,7 @@ Creates a `multiple_tree` table with the following structure: CREATE TABLE `multiple_tree` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tree` int(11) DEFAULT NULL, - `name` text NOT NULL, + `name` varchar(255) NOT NULL, `lft` int(11) NOT NULL, `rgt` int(11) NOT NULL, `depth` int(11) NOT NULL, diff --git a/migrations/m250707_103609_tree.php b/migrations/m250707_103609_tree.php index 43e0688..566c857 100644 --- a/migrations/m250707_103609_tree.php +++ b/migrations/m250707_103609_tree.php @@ -9,16 +9,22 @@ class m250707_103609_tree extends Migration public function safeUp() { $rawPrimaryKey = 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY'; + $tableOptions = []; + + if ($this->db->driverName === 'mysql') { + $tableOptions = 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'; + } $this->createTable( '{{%tree}}', [ 'id' => $this->db->driverName !== 'oci' ? $this->primaryKey()->notNull() : $rawPrimaryKey, - 'name' => $this->db->driverName === 'oci' ? $this->string()->notNull() : $this->text()->notNull(), + 'name' => $this->string(255)->notNull(), 'lft' => $this->integer()->notNull(), 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), ], + $tableOptions, ); $this->createIndex('idx_tree_lft', '{{%tree}}', 'lft'); diff --git a/migrations/m250707_104009_multiple_tree.php b/migrations/m250707_104009_multiple_tree.php index cfaf25b..2dbc23b 100644 --- a/migrations/m250707_104009_multiple_tree.php +++ b/migrations/m250707_104009_multiple_tree.php @@ -10,16 +10,21 @@ public function safeUp() { $rawPrimaryKey = 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY'; + if ($this->db->driverName === 'mysql') { + $tableOptions = 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'; + } + $this->createTable( '{{%multiple_tree}}', [ 'id' => $this->db->driverName !== 'oci' ? $this->primaryKey()->notNull() : $rawPrimaryKey, 'tree' => $this->integer()->null(), - 'name' => $this->db->driverName === 'oci' ? $this->string()->notNull() : $this->text()->notNull(), + 'name' => $this->string(255)->notNull(), 'lft' => $this->integer()->notNull(), 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), ], + $tableOptions, ); $this->createIndex('idx_multiple_tree_tree', '{{%multiple_tree}}', 'tree'); From 0fafbe5fd5baa4042f7529ca6238ea16d1ede3fe Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 7 Jul 2025 09:49:19 -0400 Subject: [PATCH 3/5] fix: ensure table options are set to `null` if not defined in `tree` and `multiple_tree` migrations. --- migrations/m250707_103609_tree.php | 3 +-- migrations/m250707_104009_multiple_tree.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/migrations/m250707_103609_tree.php b/migrations/m250707_103609_tree.php index 566c857..0ece684 100644 --- a/migrations/m250707_103609_tree.php +++ b/migrations/m250707_103609_tree.php @@ -9,7 +9,6 @@ class m250707_103609_tree extends Migration public function safeUp() { $rawPrimaryKey = 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY'; - $tableOptions = []; if ($this->db->driverName === 'mysql') { $tableOptions = 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'; @@ -24,7 +23,7 @@ public function safeUp() 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), ], - $tableOptions, + $tableOptions ?? null, ); $this->createIndex('idx_tree_lft', '{{%tree}}', 'lft'); diff --git a/migrations/m250707_104009_multiple_tree.php b/migrations/m250707_104009_multiple_tree.php index 2dbc23b..157de31 100644 --- a/migrations/m250707_104009_multiple_tree.php +++ b/migrations/m250707_104009_multiple_tree.php @@ -24,7 +24,7 @@ public function safeUp() 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), ], - $tableOptions, + $tableOptions ?? null, ); $this->createIndex('idx_multiple_tree_tree', '{{%multiple_tree}}', 'tree'); From 40335560dbe7fd9cbc808b228215b04214afdc1e Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 7 Jul 2025 10:02:18 -0400 Subject: [PATCH 4/5] docs: enhance `README.md` with detailed explanation of nested sets model and migration setup instructions. --- README.md | 70 +++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 5410a75..7cc09fb 100644 --- a/README.md +++ b/README.md @@ -59,28 +59,40 @@ composer require yii2-extensions/nested-sets-behavior ### How it works +The nested sets model is a technique for storing hierarchical data in a relational database. Unlike adjacency lists +(parent_id approach), nested sets enable efficient tree operations with minimal database queries. + 1. **Creates root nodes** using the nested sets pattern with `lft`, `rgt`, and `depth` fields. 2. **Manages hierarchy** automatically when inserting, moving, or deleting nodes. 3. **Optimizes queries** using boundary values for efficient tree traversal. 4. **Supports transactions** to ensure data integrity during complex operations. -## Database setup - -The package includes migrations to create the necessary database tables for nested sets functionality. +#### Why nested sets? -### Available migrations +- **Fast queries**: Get all descendants with a single query (`lft BETWEEN parent.lft AND parent.rgt`). +- **Efficient tree operations**: No recursive queries needed for tree traversal. +- **Automatic maintenance**: Left/right boundaries are calculated automatically. +- **Depth tracking**: Easy to limit query depth or build breadcrumbs. -The package provides two migration files. +```text +Example tree structure: +Electronics (1,12,0) +├── Mobile Phones (2,7,1) +│ └── Smartphones (3,6,1) +│ └── iPhone (4,5,2) +└── Computers (8,11,1) + └── Laptops (9,10,2) -1. **Single tree migration** (`m250707_103609_tree.php`) - for single tree per table. -2. **Multiple trees migration** (`m250707_104009_multiple_tree.php`) - for multiple independent trees. +Numbers represent: (left, right, depth) +``` -### Using package migrations +### Database setup -#### Method 1: Run migrations directly from extension (Recommended) +The package includes ready-to-use migrations for creating the necessary database structure. -Configure your console application to include the extension migrations path. +#### Quick setup (Recommended) +1. **Configure console application**: ```php [ 'class' => MigrateController::class, 'migrationPath' => [ - '@console/migrations', // Your app migrations - '@vendor/yii2-extensions/nested-sets-behavior/migrations', // Extension migrations + '@console/migrations', + '@vendor/yii2-extensions/nested-sets-behavior/migrations', ], ], ], ]; ``` -Then run migrations normally. - +2. **Run migrations**: ```bash -# View available migrations (including extension migrations) -./yii migrate/history - -# Run all pending migrations -./yii migrate - -# Or run specific migrations +# For single tree structure ./yii migrate/up m250707_103609_tree + +# For multiple trees structure ./yii migrate/up m250707_104009_multiple_tree ``` -#### Method 2: Using migration path parameter - -Run migrations directly without configuration changes. +#### Alternative: Direct migration execution ```bash -# Run single tree migration +# Run without configuration changes ./yii migrate/up --migrationPath=@vendor/yii2-extensions/nested-sets-behavior/migrations - -# Run specific migration from extension -./yii migrate/up m250707_103609_tree --migrationPath=@vendor/yii2-extensions/nested-sets-behavior/migrations ``` -### Migration details +#### Table structures created -#### Single tree migration (`m250707_103609_tree.php`) - -Creates a `tree` table with the following structure: +**Single tree** (`m250707_103609_tree.php`). Creates a `tree` table for single hierarchical structure. ```sql CREATE TABLE `tree` ( @@ -149,14 +149,12 @@ CREATE TABLE `tree` ( ); ``` -#### Multiple tree migration (`m250707_104009_multiple_tree.php`) - -Creates a `multiple_tree` table with the following structure: +**Multiple trees** (`m250707_104009_multiple_tree.php`). Creates a `multiple_tree` table for multiple independent trees. ```sql CREATE TABLE `multiple_tree` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `tree` int(11) DEFAULT NULL, + `tree` int(11) DEFAULT NULL, -- Tree identifier `name` varchar(255) NOT NULL, `lft` int(11) NOT NULL, `rgt` int(11) NOT NULL, From 89d17adca9dc7fc890ff12752145d4fdbaf3ee70 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 7 Jul 2025 10:13:38 -0400 Subject: [PATCH 5/5] fix: update SQL table creation syntax for `tree` and `multiple_tree` migrations to use standard data types and indexing. --- README.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7cc09fb..4f5b057 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,8 @@ The nested sets model is a technique for storing hierarchical data in a relation Example tree structure: Electronics (1,12,0) ├── Mobile Phones (2,7,1) -│ └── Smartphones (3,6,1) -│ └── iPhone (4,5,2) +│ └── Smartphones (3,6,2) +│ └── iPhone (4,5,3) └── Computers (8,11,1) └── Laptops (9,10,2) @@ -135,37 +135,37 @@ return [ **Single tree** (`m250707_103609_tree.php`). Creates a `tree` table for single hierarchical structure. ```sql -CREATE TABLE `tree` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `lft` int(11) NOT NULL, - `rgt` int(11) NOT NULL, - `depth` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `idx_tree_lft` (`lft`), - KEY `idx_tree_rgt` (`rgt`), - KEY `idx_tree_depth` (`depth`), - KEY `idx_tree_lft_rgt` (`lft`,`rgt`) +CREATE TABLE tree ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + lft INTEGER NOT NULL, + rgt INTEGER NOT NULL, + depth INTEGER NOT NULL ); + +CREATE INDEX idx_tree_lft ON tree (lft); +CREATE INDEX idx_tree_rgt ON tree (rgt); +CREATE INDEX idx_tree_depth ON tree (depth); +CREATE INDEX idx_tree_lft_rgt ON tree (lft, rgt); ``` **Multiple trees** (`m250707_104009_multiple_tree.php`). Creates a `multiple_tree` table for multiple independent trees. ```sql -CREATE TABLE `multiple_tree` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `tree` int(11) DEFAULT NULL, -- Tree identifier - `name` varchar(255) NOT NULL, - `lft` int(11) NOT NULL, - `rgt` int(11) NOT NULL, - `depth` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `idx_multiple_tree_tree` (`tree`), - KEY `idx_multiple_tree_lft` (`lft`), - KEY `idx_multiple_tree_rgt` (`rgt`), - KEY `idx_multiple_tree_depth` (`depth`), - KEY `idx_multiple_tree_tree_lft_rgt` (`tree`,`lft`,`rgt`) +CREATE TABLE multiple_tree ( + id INTEGER NOT NULL PRIMARY KEY, + tree INTEGER DEFAULT NULL, + name VARCHAR(255) NOT NULL, + lft INTEGER NOT NULL, + rgt INTEGER NOT NULL, + depth INTEGER NOT NULL ); + +CREATE INDEX idx_multiple_tree_tree ON multiple_tree (tree); +CREATE INDEX idx_multiple_tree_lft ON multiple_tree (lft); +CREATE INDEX idx_multiple_tree_rgt ON multiple_tree (rgt); +CREATE INDEX idx_multiple_tree_depth ON multiple_tree (depth); +CREATE INDEX idx_multiple_tree_tree_lft_rgt ON multiple_tree (tree, lft, rgt); ``` ### Basic Configuration