Skip to content

Commit 9df3187

Browse files
committed
wip: add categories
1 parent 653dc37 commit 9df3187

File tree

7 files changed

+806
-12
lines changed

7 files changed

+806
-12
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
2121
"javaabu/helpers": "^1.61",
2222
"javaabu/translatable": "^1.1",
23-
"javaabu/menu-builder": "^1.6"
23+
"javaabu/menu-builder": "^1.6",
24+
"kalnoy/nestedset": "^6.0"
2425
},
2526
"require-dev": {
2627
"laravel/pint": "^1.14",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
use Kalnoy\Nestedset\NestedSet;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Database\Migrations\Migration;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('categories', function (Blueprint $table) {
17+
$table->id();
18+
$table->foreignId('type_id');
19+
$table->string('name');
20+
$table->string('slug');
21+
$table->string('statistic_type')->nullable();
22+
$table->string('icon')->nullable();
23+
$table->string('color')->nullable();
24+
$table->unsignedInteger('order_column')->default(0)->index();
25+
NestedSet::columns($table);
26+
$table->timestamps();
27+
28+
// slugs must be unique for the category
29+
$table->unique(['slug', 'type_id'], 'unique_type_slug');
30+
31+
$table->foreign('type_id')
32+
->references('id')
33+
->on('category_types')
34+
->onDelete('cascade');
35+
36+
if (config('cms.should_translate')) $table->jsonTranslatable();
37+
});
38+
}
39+
40+
/**
41+
* Reverse the migrations.
42+
*
43+
* @return void
44+
*/
45+
public function down()
46+
{
47+
Schema::dropIfExists('categories');
48+
}
49+
};

src/Cms.php

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Support\Facades\Route;
66
use Illuminate\Support\Str;
77
use Javaabu\Cms\Enums\PostTypeFeatures;
8+
use Javaabu\Cms\Http\Controllers\Admin\CategoriesController;
89
use Javaabu\Cms\Http\Controllers\PostsController;
910
use Javaabu\Cms\Http\Controllers\Admin\PostsController as AdminPostsController;
1011
use Javaabu\Cms\Models\CategoryType;
@@ -77,21 +78,44 @@ public function registerNormalRoutes(): void
7778

7879
public function registerAdminRoutes(): void
7980
{
81+
/**
82+
* Categories
83+
*/
84+
Route::group([
85+
'prefix' => 'category-types/{category_type}',
86+
'as' => 'categories.',
87+
], function () {
88+
Route::match(['PUT', 'PATCH'], '/', [CategoriesController::class, 'bulk'])->name('bulk');
89+
Route::get('/trash', [CategoriesController::class, 'trash'])->name('trash');
90+
Route::post('/{id}/restore', [CategoriesController::class, 'restore'])->name('restore');
91+
Route::delete('/{id}/force-delete', [CategoriesController::class, 'forceDelete'])->name('force-delete');
92+
Route::get('/', [CategoriesController::class, 'index'])->name('index');
93+
Route::get('/create', [CategoriesController::class, 'create'])->name('create');
94+
Route::post('/', [CategoriesController::class, 'store'])->name('store');
95+
96+
Route::get('/{category}', [CategoriesController::class, 'show'])->name('show');
97+
Route::get('/{category}/edit', [CategoriesController::class, 'edit'])->name('edit');
98+
Route::match(['PUT', 'PATCH'], '/{category}', [CategoriesController::class, 'update'])->name('update');
99+
Route::delete('/{category}', [CategoriesController::class, 'destroy'])->name('destroy');
100+
});
101+
/**
102+
* Post Types
103+
*/
80104
Route::group([
81105
'prefix' => '{post_type}',
82106
'as' => 'posts.',
83107
], function () {
84-
Route::match(['PUT', 'PATCH'], '/', [PostsController::class, 'bulk'])->name('bulk');
85-
Route::get('/trash', [PostsController::class, 'trash'])->name('trash');
86-
Route::post('/{id}/restore', [PostsController::class, 'restore'])->name('restore');
87-
Route::delete('/{id}/force-delete', [PostsController::class, 'forceDelete'])->name('force-delete');
88-
Route::get('/', [PostsController::class, 'index'])->name('index');
89-
Route::get('/create', [PostsController::class, 'create'])->name('create');
90-
Route::post('/', [PostsController::class, 'store'])->name('store');
91-
Route::get('/{post}', [PostsController::class, 'show'])->name('show');
92-
Route::get('/{post}/edit', [PostsController::class, 'edit'])->name('edit');
93-
Route::match(['PUT', 'PATCH'], '/{post}', [PostsController::class, 'update'])->name('update');
94-
Route::delete('/{post}', [PostsController::class, 'destroy'])->name('destroy');
108+
Route::match(['PUT', 'PATCH'], '/', [AdminPostsController::class, 'bulk'])->name('bulk');
109+
Route::get('/trash', [AdminPostsController::class, 'trash'])->name('trash');
110+
Route::post('/{id}/restore', [AdminPostsController::class, 'restore'])->name('restore');
111+
Route::delete('/{id}/force-delete', [AdminPostsController::class, 'forceDelete'])->name('force-delete');
112+
Route::get('/', [AdminPostsController::class, 'index'])->name('index');
113+
Route::get('/create', [AdminPostsController::class, 'create'])->name('create');
114+
Route::post('/', [AdminPostsController::class, 'store'])->name('store');
115+
Route::get('/{post}', [AdminPostsController::class, 'show'])->name('show');
116+
Route::get('/{post}/edit', [AdminPostsController::class, 'edit'])->name('edit');
117+
Route::match(['PUT', 'PATCH'], '/{post}', [AdminPostsController::class, 'update'])->name('update');
118+
Route::delete('/{post}', [AdminPostsController::class, 'destroy'])->name('destroy');
95119
});
96120
}
97121

src/CmsServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
class CmsServiceProvider extends ServiceProvider
1515
{
1616
protected array $migrations = [
17+
'create_categories_table',
1718
'create_category_types_table',
1819
'create_post_types_table',
1920
'create_posts_table',
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
<?php
2+
3+
namespace Javaabu\Cms\Http\Controllers\Admin;
4+
5+
use Illuminate\Http\Request;
6+
use Javaabu\Cms\Http\Requests\CategoriesRequest;
7+
use Javaabu\Cms\Models\Category;
8+
use Javaabu\Cms\Models\CategoryType;
9+
use Javaabu\Helpers\Http\Controllers\Controller;
10+
use Javaabu\Helpers\Traits\HasOrderbys;
11+
class CategoriesController extends Controller
12+
{
13+
use HasOrderbys;
14+
15+
/**
16+
* Create a new controller instance.
17+
*/
18+
public function __construct()
19+
{
20+
//$this->authorizeResource(Category::class);
21+
}
22+
23+
/**
24+
* Initialize orderbys
25+
*/
26+
protected static function initOrderbys()
27+
{
28+
static::$orderbys = [
29+
'id' => _d('Id'),
30+
'created_at' => _d('Created At'),
31+
'updated_at' => _d('Updated At'),
32+
'name' => _d('Name')
33+
];
34+
}
35+
36+
/**
37+
* Display a listing of the resource.
38+
*/
39+
public function index($locale, CategoryType $type, Request $request)
40+
{
41+
$this->authorize('viewAny', $type);
42+
43+
$title = _d('All Categories');
44+
$orderby = $this->getOrderBy($request, 'created_at');
45+
$order = $this->getOrder($request, 'created_at', $orderby);
46+
$per_page = $this->getPerPage($request);
47+
48+
$categories = $type->categories()
49+
->withDepth()
50+
->defaultOrder()
51+
->orderBy($orderby, $order);
52+
53+
$search = null;
54+
if ($search = $request->input('search')) {
55+
$categories->search($search);
56+
$title = _d('Categories matching \':search\'', ['search' => $search]);
57+
}
58+
59+
if ($primary_language = $request->input('primary_language')) {
60+
$categories->whereLang($primary_language);
61+
}
62+
63+
if (! is_null($request->input('is_translated')) && $request->has('is_translated')) {
64+
if ($request->boolean('is_translated')) {
65+
$categories->whereNotNull('translations');
66+
} else {
67+
$categories->whereNull('translations');
68+
}
69+
}
70+
71+
$categories->with('type.postType')
72+
->withCount('posts', 'staffs', 'statistics');
73+
74+
// if ($request->download) {
75+
// return (new CategoriesExport($categories))->download('categories.xlsx');
76+
// }
77+
78+
$categories = $categories->paginate($per_page)
79+
->appends($request->except('page'));
80+
81+
return view('admin.categories.index', compact('categories', 'type', 'title', 'per_page', 'search'));
82+
}
83+
84+
/**
85+
* Show the form for creating a new resource.
86+
*/
87+
public function create($locale, CategoryType $type, Request $request)
88+
{
89+
$this->authorize('create', $type);
90+
91+
return view('admin.categories.create', compact('type'));
92+
}
93+
94+
/**
95+
* Store a newly created resource in storage.
96+
*/
97+
public function store($locale, CategoryType $type, CategoriesRequest $request)
98+
{
99+
$this->authorize('create', $type);
100+
101+
$category = new Category($request->validated());
102+
103+
$category->type()->associate($type);
104+
105+
$category->slug = $request->input('slug');
106+
107+
$category->lang = $request->input('lang', app()->getLocale());
108+
109+
if ($request->has('icon')) {
110+
$category->icon = $request->input('icon');
111+
}
112+
113+
if ($request->has('color')) {
114+
$category->color = $request->input('color');
115+
}
116+
117+
$category->save();
118+
119+
$category->updateSingleAttachment('featured_image', $request);
120+
121+
if ($request->expectsJson()) {
122+
return response()->json($category);
123+
}
124+
125+
$this->flashSuccessMessage();
126+
127+
return redirect()->action([CategoriesController::class, 'edit'], [$locale, $type, $category]);
128+
}
129+
130+
/**
131+
* Display the specified resource.
132+
*/
133+
public function show($locale, CategoryType $type, Category $category)
134+
{
135+
$this->authorize('view', $category);
136+
137+
return redirect()->action([CategoriesController::class, 'edit'], [$locale, $type, $category]);
138+
}
139+
140+
/**
141+
* Show the form for editing the specified resource.
142+
*/
143+
public function edit($locale, CategoryType $type, Category $category)
144+
{
145+
$this->authorize('update', $category);
146+
147+
$allowed_categories = Category::categoryList($type->id, $category->id);
148+
$category->dontShowTranslationFallbacks();
149+
return view('admin.categories.edit', compact('category', 'type', 'allowed_categories'));
150+
}
151+
152+
/**
153+
* Update the specified resource in storage.
154+
*/
155+
public function update($locale, CategoryType $type, CategoriesRequest $request, Category $category)
156+
{
157+
$this->authorize('update', $category);
158+
159+
$category->fill($request->validated());
160+
161+
if ($slug = $request->input('slug')) {
162+
$category->slug = $slug;
163+
}
164+
165+
if ($request->has('parent')) {
166+
if ($parent = $request->input('parent')) {
167+
$category->parent()->associate($parent);
168+
} else {
169+
$category->makeRoot();
170+
}
171+
}
172+
173+
if ($request->has('icon')) {
174+
$category->icon = $request->input('icon');
175+
}
176+
177+
if ($request->has('color')) {
178+
$category->color = $request->input('color');
179+
}
180+
181+
$category->hide_translation = $request->input('hide_translation', false);
182+
183+
$category->save();
184+
185+
$category->updateSingleAttachment('featured_image', $request);
186+
187+
$this->flashSuccessMessage();
188+
189+
return redirect()->action([CategoriesController::class, 'edit'], [$locale, $type, $category]);
190+
}
191+
192+
/**
193+
* Remove the specified resource from storage.
194+
*/
195+
public function destroy($locale, CategoryType $type, Category $category, Request $request)
196+
{
197+
$this->authorize('delete', $category);
198+
199+
if (! $category->delete()) {
200+
if ($request->expectsJson()) {
201+
return response()->json(false, 500);
202+
}
203+
204+
abort(500);
205+
}
206+
207+
if ($request->expectsJson()) {
208+
return response()->json(true);
209+
}
210+
211+
return redirect()->action([CategoriesController::class, 'index'], [$locale, $type]);
212+
}
213+
214+
/**
215+
* Perform bulk action on the resource
216+
*/
217+
public function bulk($locale, CategoryType $type, Request $request)
218+
{
219+
$this->authorize('viewAny', $type);
220+
221+
$this->validate($request, [
222+
'action' => 'required|in:delete',
223+
'categories' => 'required|array',
224+
'categories.*' => 'exists:categories,id,type_id,' . $type->id,
225+
]);
226+
227+
$action = $request->input('action');
228+
$ids = $request->input('categories', []);
229+
230+
switch ($action) {
231+
case 'delete':
232+
// make sure allowed to delete
233+
$this->authorize('delete', $type);
234+
235+
$type->categories()->whereIn('id', $ids)
236+
->get()
237+
->each(function (Category $category) {
238+
$category->delete();
239+
});
240+
break;
241+
}
242+
243+
$this->flashSuccessMessage();
244+
245+
return $this->redirect($request, action([CategoriesController::class, 'index'], [$locale, $type]));
246+
}
247+
}

0 commit comments

Comments
 (0)