- How do I install and set up Laravel Adjacency List for recursive tree relationships?
- Run `composer require staudenmeir/laravel-adjacency-list` and add the `HasRecursiveRelationships` trait to your Eloquent model. Ensure your table has a `parent_id` column (nullable) and optionally `path` or `depth` columns for tracking hierarchy. No additional configuration is needed for basic usage.
- Does this package support Laravel 10/11/12/13, or only older versions?
- Yes, it fully supports Laravel 10 through 13 with dedicated package versions (1.13+). Check the [compatibility table](https://github.com/staudenmeir/laravel-adjacency-list#versions) for exact version mappings. The package follows Laravel’s LTS releases and is actively maintained.
- Can I use this for many-to-many graphs (e.g., multiple parents per node) or only trees?
- This package supports both trees (one-to-many) and graphs (many-to-many). For graphs, use the `hasRecursiveGraphRelationships` trait and define a pivot table with foreign keys to parent nodes. Graphs require additional setup, like specifying a `parent_type` column for polymorphic relationships.
- Will this work with SQLite or SQL Server, or is it MySQL/PostgreSQL only?
- It works across SQLite 3.8.3+, SQL Server 2008+, and SingleStore 8.1+ (trees only). However, performance may vary—PostgreSQL and MySQL 8.0+ offer the best CTE optimization. SQLite may struggle with very deep hierarchies due to recursion limits.
- How do I handle cycles in my graph (e.g., parent-child loops) without breaking queries?
- Enable cycle detection with `enableCycleDetection()` on your relationship. This adds a `cycle_start` column to results, allowing you to filter or debug cycles. For large graphs, this may impact performance, so use it selectively or limit depth with `withMaxDepth(5)`.
- Can I customize the depth or path column names if they conflict with existing table columns?
- Yes, override the default column names by defining `getDepthName()` or `getPathName()` in your model. For example, `protected $depthName = 'custom_depth';` ensures no conflicts with existing columns like `depth` or `path`.
- How do I backfill depth/path columns for existing records in a large table?
- Use a chunked update approach to avoid memory issues. For example: `YourModel::chunk(200, function ($records) { foreach ($records as $record) { $record->update(['path' => $record->path, 'depth' => $record->depth]); } })`. For trees, this is straightforward; graphs may require more complex logic.
- Is there a performance difference between trees and graphs, and how can I optimize queries?
- Graphs are more resource-intensive due to CTE complexity. Optimize by limiting depth (`withMaxDepth()`), filtering early (`whereDepth()`), or using database indexes on `parent_id`. For read-heavy workloads, consider materialized paths (stored in the `path` column) to avoid recursion entirely.
- Can I use this with Laravel Scout for full-text search on hierarchical data?
- Yes, but you’ll need to customize the search logic to account for hierarchical relationships. Use `toTree()` or `toGraph()` to flatten results before indexing, or extend Scout’s searchable attributes to include recursive fields. Test performance with large datasets, as recursion adds overhead.
- What alternatives exist for hierarchical data in Laravel, and why choose this package?
- Alternatives include `laravel-nestedset` (for trees) or raw recursive queries. This package stands out for its CTE-based optimization (faster than application-side recursion), support for both trees/graphs, and seamless Eloquent integration. It’s ideal for complex hierarchies where performance and flexibility matter.