Skip to content

Commit 1f32ccb

Browse files
committed
category hierarchy feature
1 parent 4dde05d commit 1f32ccb

26 files changed

+2792
-36
lines changed

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
"posts",
1313
"news",
1414
"update",
15-
"webdevetc",
16-
"webdev"
15+
"hessam-blog"
1716
],
1817
"description": "Simple blog package (with admin panel) for Laravel (6.x and 7.x). Includes all views, controllers, routes and can add a blog to any existing Laravel app. Fully customisable blog (view, urls, and many other options). Includes image uploads and a pretty admin interface to manage your blog. Defaults to /blog but you can change it to anything.",
1918
"license": "MIT",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class AddParametersBlogEtcCategoriesTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('blog_etc_categories', function (Blueprint $table) {
17+
$table->integer('parent_id')->nullable();
18+
$table->integer('lft')->nullable();
19+
$table->integer('rgt')->nullable();
20+
$table->integer('depth')->nullable();
21+
});
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*
27+
* @return void
28+
*/
29+
public function down()
30+
{
31+
Schema::table('blog_etc_categories', function (Blueprint $table) {
32+
//
33+
});
34+
}
35+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
namespace WebDevEtc\BlogEtc\Baum\Extensions\Eloquent;
3+
4+
use Illuminate\Database\Eloquent\Collection as BaseCollection;
5+
6+
class Collection extends BaseCollection {
7+
8+
public function toHierarchy() {
9+
$dict = $this->getDictionary();
10+
11+
// Enforce sorting by $orderColumn setting in WebDevEtc\BlogEtc\Baum\Node instance
12+
uasort($dict, function($a, $b){
13+
return ($a->getOrder() >= $b->getOrder()) ? 1 : -1;
14+
});
15+
16+
return new BaseCollection($this->hierarchical($dict));
17+
}
18+
19+
protected function hierarchical($result) {
20+
foreach($result as $key => $node)
21+
$node->setRelation('children', new BaseCollection);
22+
23+
$nestedKeys = array();
24+
25+
foreach($result as $key => $node) {
26+
$parentKey = $node->getParentId();
27+
28+
if ( !is_null($parentKey) && array_key_exists($parentKey, $result) ) {
29+
$result[$parentKey]->children[] = $node;
30+
31+
$nestedKeys[] = $node->getKey();
32+
}
33+
}
34+
35+
foreach($nestedKeys as $key)
36+
unset($result[$key]);
37+
38+
return $result;
39+
}
40+
41+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
namespace WebDevEtc\BlogEtc\Baum\Extensions\Eloquent;
3+
4+
use Illuminate\Database\Eloquent\Model as BaseModel;
5+
use Illuminate\Database\Eloquent\ModelNotFoundException;
6+
use Illuminate\Database\Eloquent\SoftDeletingScope;
7+
use WebDevEtc\BlogEtc\Baum\Extensions\Query\Builder as QueryBuilder;
8+
9+
abstract class Model extends BaseModel {
10+
11+
/**
12+
* Reloads the model from the database.
13+
*
14+
* @return \Baum\Node
15+
*
16+
* @throws ModelNotFoundException
17+
*/
18+
public function reload() {
19+
if ( $this->exists || ($this->areSoftDeletesEnabled() && $this->trashed()) ) {
20+
$fresh = $this->getFreshInstance();
21+
22+
if ( is_null($fresh) )
23+
throw with(new ModelNotFoundException)->setModel(get_called_class());
24+
25+
$this->setRawAttributes($fresh->getAttributes(), true);
26+
27+
$this->setRelations($fresh->getRelations());
28+
29+
$this->exists = $fresh->exists;
30+
} else {
31+
// Revert changes if model is not persisted
32+
$this->attributes = $this->original;
33+
}
34+
35+
return $this;
36+
}
37+
38+
/**
39+
* Get the observable event names.
40+
*
41+
* @return array
42+
*/
43+
public function getObservableEvents() {
44+
return array_merge(array('moving', 'moved'), parent::getObservableEvents());
45+
}
46+
47+
/**
48+
* Register a moving model event with the dispatcher.
49+
*
50+
* @param Closure|string $callback
51+
* @return void
52+
*/
53+
public static function moving($callback, $priority = 0) {
54+
static::registerModelEvent('moving', $callback, $priority);
55+
}
56+
57+
/**
58+
* Register a moved model event with the dispatcher.
59+
*
60+
* @param Closure|string $callback
61+
* @return void
62+
*/
63+
public static function moved($callback, $priority = 0) {
64+
static::registerModelEvent('moved', $callback, $priority);
65+
}
66+
67+
/**
68+
* Get a new query builder instance for the connection.
69+
*
70+
* @return \Baum\Extensions\Query\Builder
71+
*/
72+
protected function newBaseQueryBuilder() {
73+
$conn = $this->getConnection();
74+
75+
$grammar = $conn->getQueryGrammar();
76+
77+
return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
78+
}
79+
80+
/**
81+
* Returns a fresh instance from the database.
82+
*
83+
* @return \Baum\Node
84+
*/
85+
protected function getFreshInstance() {
86+
if ( $this->areSoftDeletesEnabled() )
87+
return static::withTrashed()->find($this->getKey());
88+
89+
return static::find($this->getKey());
90+
}
91+
92+
/**
93+
* Returns wether soft delete functionality is enabled on the model or not.
94+
*
95+
* @return boolean
96+
*/
97+
public function areSoftDeletesEnabled() {
98+
// To determine if there's a global soft delete scope defined we must
99+
// first determine if there are any, to workaround a non-existent key error.
100+
$globalScopes = $this->getGlobalScopes();
101+
102+
if ( count($globalScopes) === 0 ) return false;
103+
104+
// Now that we're sure that the calling class has some kind of global scope
105+
// we check for the SoftDeletingScope existance
106+
return static::hasGlobalScope(new SoftDeletingScope);
107+
}
108+
109+
/**
110+
* Static method which returns wether soft delete functionality is enabled
111+
* on the model.
112+
*
113+
* @return boolean
114+
*/
115+
public static function softDeletesEnabled() {
116+
return with(new static)->areSoftDeletesEnabled();
117+
}
118+
119+
}

src/Baum/Extensions/Query/Builder.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace WebDevEtc\BlogEtc\Baum\Extensions\Query;
4+
5+
use Illuminate\Database\Query\Builder as BaseBuilder;
6+
7+
class Builder extends BaseBuilder {
8+
9+
/**
10+
* Replace the "order by" clause of the current query.
11+
*
12+
* @param string $column
13+
* @param string $direction
14+
* @return \Illuminate\Database\Query\Builder|static
15+
*/
16+
public function reOrderBy($column, $direction = 'asc') {
17+
$this->orders = null;
18+
19+
if ( !is_null($column) ) return $this->orderBy($column, $direction);
20+
21+
return $this;
22+
}
23+
24+
/**
25+
* Execute an aggregate function on the database.
26+
*
27+
* @param string $function
28+
* @param array $columns
29+
* @return mixed
30+
*/
31+
public function aggregate($function, $columns = array('*')) {
32+
// Postgres doesn't like ORDER BY when there's no GROUP BY clause
33+
if ( !isset($this->groups) )
34+
$this->reOrderBy(null);
35+
36+
return parent::aggregate($function, $columns);
37+
}
38+
39+
}

0 commit comments

Comments
 (0)