Trees
Simple tree
It is built by adding a field of type Parent parent to the model, which stores the id of the parent of the current record. For root records, the value of this field is -1.
An example of simple use of a tree when creating a menu of nested pages.
class Pages extends Model
{
protected $name = 'Pages menu';
protected $model_elements = [
['Active', 'bool', 'active', ['on_create' => true]],
['Show in menu', 'bool', 'in_menu', ['on_create' => true]],
['Name', 'char', 'name', ['required' => true]],
['Prent section', 'parent', 'parent', ['max_depth' => 3]],
['Position', 'order', 'order'],
['Content', 'text', 'content', ['rich_text' => true]]
];
}
Linked tree
To create a structure like catalog -> catalog -> catalog -> product or album -> album -> image, you need to link the model with the parent field to another model so that the final parent of the first model is a foreign key for the records of the other model.
An example of creating a linked tree for a multi-level product catalog.
class Catalogs extends Model
{
protected $name = 'Catalog sections';
protected $model_elements = [
['Active', 'bool', 'active', ['on_create' => true]],
['Name', 'char', 'name', ['required' => true]],
['Catalog', 'parent', 'parent', ['parent_for' => 'Products']],
['Link', 'url', 'url'],
['Position', 'order', 'order']
];
}
class Products extends Model
{
protected $name = 'Catalog products';
protected $model_elements = [
['Active', 'bool', 'active', ['on_create' => true]],
['Name', 'char', 'name', ['required' => true]],
['Catalog Section', 'enum', 'parent', ['foreign_key' => 'Catalogs',
'is_parent' => true]],
['Price', 'int', 'price', ['required' => true]],
['Images', 'multi_images','images'],
['Description', 'text', 'desc', ['rich_text' => true]],
['Position', 'order', 'order']
];
}
Special tree methods
Special methods are provided for quick access to parents and descendants in the tree.
- getParents($id) - returns an array of parent records (up to the record with the parent field value equal to -1). In the resulting array, the keys are the record ids, the values are the record names according to the $name_field parameter from the Model setup section.
- getChildren($id) - returns an array of all child records, recursively traversing all tree branches. The resulting array is built similarly to the previous method.
displayBreadcrumbs($id, $url_first [, $url_field]) - displays the link path to the entry with the passed id. Returns a sequence of html tags in the form: link -> link -> link -> span.
Input parameters:
$id of the current entry
$url_first - the first part of the url, optional parameter
$url_field - the name of the field that stores the text link for this entry (for constructing a url like /catalog/toys).
For the pre-installed Pages model, links are automatically built as /page/4 and /contacts (without the first part).
//Search for a record
$catalog = $mv -> catalogs -> find(43);
//Parent records
$parents = $mv -> catalogs -> getParents($catalog -> id);
Debug::pre($parents);
//Child records
$children = $mv -> catalogs -> getChildren($catalog -> id);
Debug::pre($children);
//Reference path for a catalog section
echo $mv -> catalogs -> displayBreadcrumbs($catalog -> id, 'category', 'url');
//Reference path for the catalog product
//The result will be in the form of links: Toys -> Balls -> Red ball
echo $mv -> products -> displayBreadcrumbs($product -> id, 'category');
The listed methods can also be called from within the model object. In the example below, the catalog page is determined based on the passed URL.
class Catalogs extends Model
{
...
//Search for an active entry by URL like '/catalog/23' or '/catalog/tools'
//Route like '/catalog/*' => 'view-catalog.php' in file 'config/routes.php'
public function defineCatalog(Router $router)
{
$url_parts = $router -> getUrlParts();
$record = null;
if(is_numeric($url_parts[1]))
$record = $this -> find(['id' => $url_parts[1], 'active' => 1]);
else
$record = $this -> find(['url' => $url_parts[1], 'active' => 1]);
if($record !== null)
{
$this -> id = $record -> id;
$this -> parents = $this -> getParents($record -> id);
}
return $record;
}
Recursively build the catalog menu in the Catalogs model.
<?
public function displayCatalogMenu($parent)
{
//Root section or next deepest section recursively
$rows = $this -> select(['parent' => $parent, 'active' => 1, 'order->asc' => 'order']);
$root_path = $this -> root_path.'catalog/';
$html = '';
foreach($rows as $row)
{
//Active menu item
$active = '';
//Child elements
$children = [];
//We search for child elements and set the active item
if($row['id'] == $this -> id || array_key_exists($row['id'], $this -> parents))
{
$children = $this -> select(['parent' => $row['id'], 'active' => 1]);
$active = ' class="active"';
}
//Forming a link
$url = $root_path.($row['url'] ? $row['url'] : $row['id']);
$html .= '<li".$active."><a href="'.$url.'">'.$row['name'].'</a>';
//We output child elements if they exist
if(count($children) > 0)
$html .= '<ul>'.$this -> displayCatalogMenu($row['id']).'</ul>';
$html .= '</li>';
}
return $html;
}
Previous section
Foreign keys