This abstract class implements Nested Set functionality. A Nested Set is a smart way to implement an ordered tree with the added benefit that you can select all of their descendants with a single query. Drawbacks are that insertion or move operations need more complex sql queries. Nested sets are appropiate when you want either an ordered tree (menus, commercial categories, etc.) or an efficient way of querying big trees.
Inheritance: extends Baum\Extensions\Eloquent\Model
Example #1
0
 protected static function boot()
 {
     parent::boot();
     static::deleting(function ($model) {
         $model->prepareForDelete();
     });
 }
Example #2
0
 protected static function boot()
 {
     parent::boot();
     static::creating(function ($cluster) {
         $cluster->ensureUuid();
     });
 }
 /**
  * Renders the specified category and it's children in single dimension array.
  *
  * @param Node $node
  *
  * @return array
  */
 public static function getRenderedNode(Node $node)
 {
     $options = [];
     if ($node->isRoot()) {
         $name = $node->name;
     } else {
         $depth = str_repeat('--', $node->depth);
         $name = sprintf('%s %s', $depth, $node->name);
     }
     $options[$node->id] = $name;
     if ($node->children()->count() > 0) {
         foreach ($node->children as $child) {
             $options = $options + static::getRenderedNode($child);
         }
     }
     return $options;
 }
Example #4
0
 protected static function boot()
 {
     parent::boot();
     // When deleting we should also clean up any relationships
     static::deleting(function ($model) {
         $model->images()->detach();
     });
 }
Example #5
0
 /**
  * Show the Dashboard.
  *
  * @return Response
  */
 public function getIndex()
 {
     $id = \Input::get('id') ?: null;
     $name = \Input::get('column_name') ? explode(',', \Input::get('column_name')) : null;
     $tableName = \Input::get('table_name') ?: null;
     $moduleName = \Input::get('name') ?: null;
     $output = array();
     // Instantiate model
     $modelName = studly_case(str_singular($tableName));
     $model = '\\Orangehill\\Photon\\' . $modelName;
     if (!class_exists($model)) {
         $model = '\\' . $modelName;
     }
     $this->modelInstance = new $model();
     if (is_null($id)) {
         // Get roots
         $entries = $this->modelInstance->roots()->get();
     } else {
         // Get parent by id
         $parent = $this->modelInstance->find($id);
         // Get children
         $entries = $parent->children()->get();
     }
     foreach ($entries as $entry) {
         $node = array();
         // Check if entry name is from one to many relation
         //            $entry->$name = $this->checkOneToManyRelation($name, $entry);
         if ($name === null) {
             $entryName = (string) $entry;
         } else {
             $entryNameElements = array();
             array_walk($name, function ($value) use(&$entry, &$entryNameElements) {
                 $entryNameElements[] = $entry->{$value};
             });
             $entryName = join(' ', $entryNameElements);
         }
         $node['data'] = array('title' => $entryName, 'attr' => array('href' => '/admin/' . $moduleName . '/' . $entry->id));
         $node['attr'] = array('data-module-name' => $moduleName, 'id' => $moduleName . '_' . $entry->id);
         if (count($entry->children()->get())) {
             $node['state'] = 'closed';
         }
         $output[] = $node;
     }
     return \Response::json($output);
 }
Example #6
0
 public function delete()
 {
     // delete all related fields
     foreach ($this->fields as $field) {
         $field->delete();
     }
     // delete the module
     return parent::delete();
 }
Example #7
0
 public static function boot()
 {
     parent::boot();
     //        App::register($this->service_provider);
     //we need to fill in all the defaults for this item..
     Content::created(function ($content) {
         //we need check for sub pages and create them!
     });
 }
Example #8
0
File: Menu.php Project: zedx/core
 protected static function boot()
 {
     parent::boot();
     static::moved(function ($menu) {
         event(new MenuWasMoved($menu));
     });
     static::deleted(function ($menu) {
         event(new MenuWasDeleted($menu));
     });
 }
Example #9
0
 /**
  * The "booting" method of the model.
  *
  * @return void
  */
 protected static function boot()
 {
     parent::boot();
     static::updating(function ($category) {
         // Baum triggers a parent move, which puts the item last in the list, even if the old and new parents are the same
         if ($category->isParentIdSame()) {
             $category->stopBaumParentMove();
         }
     });
 }
Example #10
0
 /**
  * The "booting" method of the model.
  *
  * @return void
  */
 protected static function boot()
 {
     parent::boot();
     static::updating(function ($navItem) {
         $dirty = $navItem->getDirty();
         $oldNavItem = self::where('id', '=', $navItem->id)->first();
         $oldParent = $oldNavItem->parent;
         $oldParentId = $oldParent->id;
         if (isset($dirty[$navItem->getParentColumnName()]) && $dirty[$navItem->getParentColumnName()] == $oldParentId) {
             unset($navItem->{$navItem->getParentColumnName()});
             static::$moveToNewParentId = FALSE;
         }
     });
 }
Example #11
0
 /**
  * Checks if duplicate values for the column specified exist. Takes
  * the Nested Set scope columns into account (if appropiate).
  *
  * @param   string  $column
  * @return  boolean
  */
 protected function duplicatesExistForColumn($column)
 {
     $connection = $this->node->getConnection();
     $grammar = $connection->getQueryGrammar();
     $columns = array_merge($this->node->getQualifiedScopedColumns(), array($column));
     $columnsForSelect = implode(', ', array_map(function ($col) use($grammar) {
         return $grammar->wrap($col);
     }, $columns));
     $wrappedColumn = $grammar->wrap($column);
     $query = $this->node->newQuery()->select($connection->raw("{$columnsForSelect}, COUNT({$wrappedColumn})"))->havingRaw("COUNT({$wrappedColumn}) > 1");
     foreach ($columns as $col) {
         $query->groupBy($col);
     }
     $result = $query->first();
     return !is_null($result);
 }
 /**
  * Deletes a single field via ajax call (used to delete an image without deleting entire entry)
  *
  * @return object
  */
 public function deleteField()
 {
     // Get the values
     $id = \Input::get('id');
     $column_name = \Input::get('column_name');
     // Get the entry record
     $entry = $this->modelInstance->find($id);
     // Remove the file
     $module_storage_path = \public_path() . '/media/' . $this->data['module']->table_name;
     \File::delete($module_storage_path . '/' . $entry[$column_name]);
     // Set selected field to null
     $entry[$column_name] = null;
     // Save entry
     $entry->save();
     // Render the view
     return \Response::json(array('Success'));
 }
Example #13
0
 public static function boot()
 {
     parent::boot();
     static::creating(function ($model) {
         if (Schema::hasColumn($model->getTable(), 'created_at')) {
             $model->created_at = date('Y-m-d H:i:s');
         }
         if (Schema::hasColumn($model->getTable(), 'created_by') && !$model->created_by) {
             $model->created_by = Auth::check() ? Auth::user()->id : 0;
         }
     });
     static::saving(function ($model) {
         if (Schema::hasColumn($model->getTable(), 'updated_by') && !$model->updated_by) {
             $model->updated_by = Auth::check() ? Auth::user()->id : 0;
         }
     });
 }
Example #14
0
 public function getAttribute($key)
 {
     if ($key == 'name' && $this->region_type_id == 1) {
         return $this->country->name;
     }
     if (str_contains($key, ':')) {
         list($key, $locale) = explode(':', $key);
     } else {
         $locale = $this->locale();
     }
     if ($this->isTranslationAttribute($key)) {
         if ($this->getTranslation($locale) === null) {
             return;
         }
         return $this->getTranslation($locale)->{$key};
     }
     return parent::getAttribute($key);
 }
Example #15
0
 protected static function boot()
 {
     parent::boot();
     static::created(function ($category) {
         event(new CategoryWasCreated($category));
     });
     static::moved(function ($category) {
         event(new CategoryWasMoved($category));
     });
     static::deleted(function ($category) {
         event(new CategoryWasDeleted($category));
     });
     static::deleting(function ($category) {
         foreach ($category->ads as $ad) {
             $ad->forceDelete();
         }
         $category->codes()->delete();
         $category->fields()->detach();
     });
 }
Example #16
0
 /**
  * List permission of role
  *
  * @param user id
  * @return json
  */
 public function rolePerm($roleId)
 {
     $role = new PermissionRole();
     $tree = parent::where('id', '=', $this->getRootNode()->id)->first()->getDescendants()->toHierarchy();
     // Get list permission with status
     $permissions = $role->getRolePermission($roleId, $tree->toArray());
     return $permissions;
 }
Example #17
0
 /**
  * Return an array with the last node we could reach and its nesting level.
  *
  * @param   \Baum\Node $node
  * @param   int $nesting
  * @return  array
  */
 protected function determineDepth($node, $nesting = 0)
 {
     // Traverse back up the ancestry chain and add to the nesting level count
     while ($parent = $node->parent()->first()) {
         $nesting = $nesting + 1;
         $node = $parent;
     }
     return [$node, $nesting];
 }
Example #18
0
 protected static function boot()
 {
     parent::boot();
     static::deleting(function ($task) {
         $task->comments()->delete();
         $task->activities()->delete();
         $task->children()->delete();
     });
 }
Example #19
0
 public function __construct()
 {
     $this->table = config('laraboard.table_prefix') . $this->table;
     parent::__construct();
 }
Example #20
0
 /**
  * Return an array of the scoped attributes of the supplied node.
  *
  * @param   Baum\Node $node
  * @return  array
  */
 protected function scopedAttributes($node)
 {
     $keys = $this->node->getScopedColumns();
     if (count($keys) == 0) {
         return array();
     }
     $values = array_map(function ($column) use($node) {
         return $node->getAttribute($column);
     }, $keys);
     return array_combine($keys, $values);
 }
Example #21
0
 /**
  * The "booting" method of the model.
  *
  * @return void
  */
 protected static function boot()
 {
     // Do not forget this!
     parent::boot();
     static::moving(function ($node) {
         // YOUR CODE HERE
     });
     static::moved(function ($node) {
         // YOUR CODE HERE
     });
 }
Example #22
0
 protected function performSave()
 {
     // there are two situation here, an orthodox form submittal and a ajax one:
     // - the orthodox will send a json string
     // - the ajax version will send an array
     $var = \Input::get($this->name);
     if (is_string($var)) {
         $var = json_decode($var, true);
     }
     $movements = [];
     $subtreeId = $this->source->getKey();
     // We now invert the order of movements and group/sort them by
     // depth. This is done to avoid the situation where a node wants
     // to become the descendant of one of its own descendants.
     // This kind of sort will prevent the issue ensuring all the descendants
     // are moved first.
     $this->sortMovementsByDepth($var, $movements, $subtreeId);
     ksort($movements);
     $movements = call_user_func_array('array_merge', $movements);
     $movements = Collection::make($movements)->keyBy('id');
     /** @var \Baum\Extensions\Eloquent\Collection $nodes */
     $root = $this->source->getRoot();
     // store depth and left ot the root, to build upon when
     // we will rebuild the tree.
     $rootDepth = $root->depth;
     $rootLeft = $root->lft;
     // now we read the entire tree. We need to do that because
     // of the nested set way workings: Baum provides handy methods
     // to move the nodes, but they trigger an awful lot of queries.
     // We'd rather read the whole tree once instead, and perform all
     // the calculations in-memory.
     $nodes = $root->getDescendantsAndSelf([$this->source->getKeyName(), 'lft', 'rgt', 'depth', 'parent_id']);
     // the ids of all the moved elements
     $movedIds = $movements->keys()->toArray();
     // index the elements by primary key for speedy retrieval
     $dictionary = $nodes->getDictionary();
     // the elements of the bigger tree that did not change their
     // parent_id
     $unmoved = new \Baum\Extensions\Eloquent\Collection();
     foreach ($dictionary as $n) {
         if (!in_array($n->getKey(), $movedIds)) {
             $unmoved[] = $n;
         }
     }
     // the elements that were moved to a different parent
     $moved = new \Baum\Extensions\Eloquent\Collection();
     foreach ($movedIds as $i) {
         $moved[] = $dictionary[$i];
     }
     // this is the column that Baum uses to order the tree
     // the default is `lft`
     $orderColumn = $this->source->getOrderColumnName();
     // we backup the order column, because we have to mess with
     // it later and we want to be able to restore it so we can
     // still use `$node->isDirty()` to see if the the node needs
     // to be updated or not.
     foreach ($dictionary as $n) {
         $n->__order = $n->{$orderColumn};
     }
     // what now? We put all the moved nodes before the rest of the
     // tree. This way they'll be put before their unmoved siblings
     // shall they exist.
     $orderedNodes = $moved->merge($unmoved);
     // shady stuff going on here: Baum collections build the hierarchy
     // based on parent id AND the order column (lft). We thus update the
     // order column with an incremental value to be sure the siblings
     // order is preserved.
     $order = 1;
     foreach ($orderedNodes as $n) {
         $n->{$orderColumn} = $order++;
         if (isset($movements[$n->getKey()])) {
             // is the parent_id changed? If so, let's update it
             $n->parent_id = $movements[$n->getKey()]['parent_id'];
         }
     }
     // let Baum build the new tree
     $newTree = $orderedNodes->toHierarchy();
     // lets restore the order column and delete the previous backup,
     // so we can use `$node->isDirty` later
     foreach ($dictionary as $n) {
         $n->{$orderColumn} = $n->__order;
         unset($n->__order);
     }
     // if everything worked correctly we should have a nested collection
     // with only one root element. The root ID should be unchanged.
     $newRoot = $newTree->first();
     if ($newRoot->getKey() != $root->getKey() || count($newTree) != 1) {
         throw new \LogicException("Invalid tree");
     }
     // now we take the new tree and recursively recalculate the left, right
     // and depth fields.
     $left = $rootLeft - 1;
     $depth = $rootDepth;
     $reindex = function ($tree, $reindex, $depth) use(&$left) {
         foreach ($tree as $node) {
             $left++;
             $node->lft = $left;
             $node->depth = $depth;
             $reindex($node->getRelation('children'), $reindex, $depth + 1);
             $left++;
             $node->rgt = $left;
         }
     };
     $reindex($newTree, $reindex, $depth);
     // compute the changes and only save the changed ones!
     $bulk = [];
     foreach ($dictionary as $n) {
         if ($n->isDirty()) {
             $bulk[$n->getKey()] = ['lft' => $n->lft, 'rgt' => $n->rgt, 'depth' => $n->depth, 'parent_id' => $n->parent_id];
         }
     }
     foreach ($bulk as $id => $fields) {
         \DB::table($this->source->getTable())->where($this->source->getKeyName(), $id)->update($fields);
     }
 }
Example #23
0
 protected function wrapInTransaction(Closure $callback)
 {
     return $this->node->getConnection()->transaction($callback);
 }
Example #24
0
 /**
  * To Array
  *
  * Wraps the default toArray method so that key names are
  * converted to camelCase for API handling.
  *
  * @return array
  */
 public function toArray()
 {
     $data = parent::toArray();
     return Config::get('c4tech.jsonify_output', true) ? $this->convertToCamelCase($data) : $data;
 }
Example #25
0
 /**
  * Get the fully qualified value for the specified column.
  *
  * @return string
  */
 protected function qualify($column)
 {
     return $this->node->getTable() . '.' . $column;
 }
Example #26
0
 public function __construct(array $attributes = array())
 {
     $this->setTable(\Request::segment(3));
     parent::__construct($attributes);
 }
Example #27
0
 /**
  * Create a new Eloquent model instance.
  *
  * @param  array  $attributes
  * @return void
  */
 public function __construct(array $attributes = [])
 {
     parent::__construct($attributes);
     $this->__initEntity();
 }
 /**
  * Make current page a root page, provided that a page
  * with the same scope does not exist.
  *
  * @return PageNode
  */
 public function makeRoot()
 {
     // guard agains root with the same scope
     $present = $this->newQuery()->where($this->getScopedConditions())->whereNull($this->getParentColumnName())->count() > 0;
     if ($present) {
         throw new \Baum\MoveNotPossibleException();
     }
     return parent::makeRoot();
 }
Example #29
0
File: Move.php Project: yajra/baum
 /**
  * Applies a lock to the rows between the supplied index boundaries.
  *
  * @param   int   $lft
  * @param   int   $rgt
  * @return  void
  */
 protected function applyLockBetween($lft, $rgt)
 {
     $this->node->newQuery()->where($this->node->getLeftColumnName(), '>=', $lft)->where($this->node->getRightColumnName(), '<=', $rgt)->select($this->node->getKeyName())->lockForUpdate()->get();
 }
Example #30
0
 /**
  * @param \Baum\Node $node
  * @param array $items
  * @return array
  */
 protected function appendMenu($node, &$items)
 {
     $items[] = ['title' => $node->present()->indentedTitle(), 'id' => $node->id];
     if (count($node->children)) {
         foreach ($node->children as $child) {
             foreach ($child->getDescendantsAndSelf()->toHierarchy() as $menu) {
                 $this->appendMenu($menu, $items);
             }
         }
     }
 }