123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- <?php
- namespace Encore\Admin\Traits;
- use Illuminate\Database\Eloquent\Model;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Request;
- trait ModelTree
- {
- /**
- * @var array
- */
- protected static $branchOrder = [];
- /**
- * @var string
- */
- protected $parentColumn = 'parent_id';
- /**
- * @var string
- */
- protected $titleColumn = 'title';
- /**
- * @var string
- */
- protected $orderColumn = 'order';
- /**
- * @var \Closure
- */
- protected $queryCallback;
- /**
- * Get children of current node.
- *
- * @return \Illuminate\Database\Eloquent\Relations\HasMany
- */
- public function children()
- {
- return $this->hasMany(static::class, $this->parentColumn);
- }
- /**
- * Get parent of current node.
- *
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
- */
- public function parent()
- {
- return $this->belongsTo(static::class, $this->parentColumn);
- }
- /**
- * @return string
- */
- public function getParentColumn()
- {
- return $this->parentColumn;
- }
- /**
- * Set parent column.
- *
- * @param string $column
- */
- public function setParentColumn($column)
- {
- $this->parentColumn = $column;
- }
- /**
- * Get title column.
- *
- * @return string
- */
- public function getTitleColumn()
- {
- return $this->titleColumn;
- }
- /**
- * Set title column.
- *
- * @param string $column
- */
- public function setTitleColumn($column)
- {
- $this->titleColumn = $column;
- }
- /**
- * Get order column name.
- *
- * @return string
- */
- public function getOrderColumn()
- {
- return $this->orderColumn;
- }
- /**
- * Set order column.
- *
- * @param string $column
- */
- public function setOrderColumn($column)
- {
- $this->orderColumn = $column;
- }
- /**
- * Set query callback to model.
- *
- * @param \Closure|null $query
- *
- * @return $this
- */
- public function withQuery(\Closure $query = null)
- {
- $this->queryCallback = $query;
- return $this;
- }
- /**
- * Format data to tree like array.
- *
- * @return array
- */
- public function toTree()
- {
- return $this->buildNestedArray();
- }
- /**
- * Build Nested array.
- *
- * @param array $nodes
- * @param int $parentId
- *
- * @return array
- */
- protected function buildNestedArray(array $nodes = [], $parentId = 0)
- {
- $branch = [];
- if (empty($nodes)) {
- $nodes = $this->allNodes();
- }
- foreach ($nodes as $node) {
- if ($node[$this->parentColumn] == $parentId) {
- $children = $this->buildNestedArray($nodes, $node[$this->getKeyName()]);
- if ($children) {
- $node['children'] = $children;
- }
- $branch[] = $node;
- }
- }
- return $branch;
- }
- /**
- * Get all elements.
- *
- * @return mixed
- */
- public function allNodes()
- {
- $orderColumn = DB::getQueryGrammar()->wrap($this->orderColumn);
- $byOrder = $orderColumn.' = 0,'.$orderColumn;
- $self = new static();
- if ($this->queryCallback instanceof \Closure) {
- $self = call_user_func($this->queryCallback, $self);
- }
- return $self->orderByRaw($byOrder)->get()->toArray();
- }
- /**
- * Set the order of branches in the tree.
- *
- * @param array $order
- *
- * @return void
- */
- protected static function setBranchOrder(array $order)
- {
- static::$branchOrder = array_flip(array_flatten($order));
- static::$branchOrder = array_map(function ($item) {
- return ++$item;
- }, static::$branchOrder);
- }
- /**
- * Save tree order from a tree like array.
- *
- * @param array $tree
- * @param int $parentId
- */
- public static function saveOrder($tree = [], $parentId = 0)
- {
- if (empty(static::$branchOrder)) {
- static::setBranchOrder($tree);
- }
- foreach ($tree as $branch) {
- $node = static::find($branch['id']);
- $node->{$node->getParentColumn()} = $parentId;
- $node->{$node->getOrderColumn()} = static::$branchOrder[$branch['id']];
- $node->save();
- if (isset($branch['children'])) {
- static::saveOrder($branch['children'], $branch['id']);
- }
- }
- }
- /**
- * Get options for Select field in form.
- *
- * @param \Closure|null $closure
- * @param string $rootText
- *
- * @return array
- */
- public static function selectOptions(\Closure $closure = null, $rootText = 'Root')
- {
- $options = (new static())->withQuery($closure)->buildSelectOptions();
- return collect($options)->prepend($rootText, 0)->all();
- }
- /**
- * Build options of select field in form.
- *
- * @param array $nodes
- * @param int $parentId
- * @param string $prefix
- *
- * @return array
- */
- protected function buildSelectOptions(array $nodes = [], $parentId = 0, $prefix = '')
- {
- $prefix = $prefix ?: str_repeat(' ', 6);
- $options = [];
- if (empty($nodes)) {
- $nodes = $this->allNodes();
- }
- foreach ($nodes as $node) {
- $node[$this->titleColumn] = $prefix.' '.$node[$this->titleColumn];
- if ($node[$this->parentColumn] == $parentId) {
- $children = $this->buildSelectOptions($nodes, $node[$this->getKeyName()], $prefix.$prefix);
- $options[$node[$this->getKeyName()]] = $node[$this->titleColumn];
- if ($children) {
- $options += $children;
- }
- }
- }
- return $options;
- }
- /**
- * {@inheritdoc}
- */
- public function delete()
- {
- $this->where($this->parentColumn, $this->getKey())->delete();
- return parent::delete();
- }
- /**
- * {@inheritdoc}
- */
- protected static function boot()
- {
- parent::boot();
- static::saving(function (Model $branch) {
- $parentColumn = $branch->getParentColumn();
- if (Request::has($parentColumn) && Request::input($parentColumn) == $branch->getKey()) {
- throw new \Exception(trans('admin.parent_select_error'));
- }
- if (Request::has('_order')) {
- $order = Request::input('_order');
- Request::offsetUnset('_order');
- static::tree()->saveOrder($order);
- return false;
- }
- return $branch;
- });
- }
- }
|