diff --git a/app/Http/Controllers/Api/Pages/PagesController.php b/app/Http/Controllers/Api/Pages/PagesController.php new file mode 100644 index 0000000..9b76e7d --- /dev/null +++ b/app/Http/Controllers/Api/Pages/PagesController.php @@ -0,0 +1,47 @@ +model = $model; + } + + public function root(Request $request): JsonResponse { + return fractal(Page::root(), new PageTransformer())->respond(); + } + + public function index(Request $request): JsonResponse { + $query = $this->model->query(); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new PageTransformer())->respond(); + } + + public function show($id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + return fractal($model, new PageTransformer())->respond(); + } + + + public function store(Request $request): void { + } + + + public function update(Request $request, $uuid): void { + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } + +} diff --git a/app/Models/Pages/Page.php b/app/Models/Pages/Page.php new file mode 100644 index 0000000..26541cc --- /dev/null +++ b/app/Models/Pages/Page.php @@ -0,0 +1,88 @@ +belongsTo(Page::class, 'parent_id'); + } + + public function children(): HasMany { + return $this->hasMany(Page::class, 'parent_id'); + } + + public function sections(): MorphToMany { + return $this->objects()->whereHas('type.parent', function($query) { + $query->where(['name' => 'page-section']); + }); + } + + public function sidebar(): Model { + return $this->getObject('page-sidebar'); + } + public function sidebars(): MorphToMany { + return $this->objects()->whereHas('type', function($query) { + $query->where(['name' => 'page-sidebar']); + }); + } + + + public function getLinkAttribute(): string { + return $this->parents->reverse()->push($this)->pluck('slug')->implode('/'); + } + + public function getParentsAttribute(): Collection { + $page = $this; + $result = collect([]); + while($page = $page->parent) $result->push($page); + return $result; + } + + public function getParsedTypeAttribute(): array { + return ['name' => $this->type, 'title' => PageType::TITLES[$this->type] ?? null]; + } + + + + public function addSection($typeName, $ord) { + $this->createObject($typeName, $ord); + } + + + + public static function root() { + return self::query()->where(['parent_id' => 0])->get(); + } + +} diff --git a/app/Models/Pages/PageType.php b/app/Models/Pages/PageType.php new file mode 100644 index 0000000..d9dd9bb --- /dev/null +++ b/app/Models/Pages/PageType.php @@ -0,0 +1,11 @@ + 'Контентная страница' + ]; +} \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0834998..e5a0505 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,47 +2,18 @@ namespace App\Providers; -use App\Models\Advisories\Advisory; -use App\Models\Advisories\AdvisoryMember; -use App\Models\Advisories\AdvisorySession; -use App\Models\Advisories\SessionInvitation; -use App\Models\Applications\Application; use App\Models\Asset; -use App\Models\Catalog\Category; -use App\Models\Classification\Classifier; -use App\Models\Classification\Code; -use App\Models\Companies\Address; -use App\Models\Companies\BankDetails; -use App\Models\Companies\Company; -use App\Models\Companies\CompanyMember; -use App\Models\Companies\Contact; -use App\Models\Companies\Department; -use App\Models\Correspondence\Letter; use App\Models\Dictionaries\Dictionary; use App\Models\Dictionaries\DictionaryItem; -use App\Models\Normatives\Development\Development; -use App\Models\Normatives\Development\DevelopmentStage; -use App\Models\Normatives\Normative; -use App\Models\Normatives\Plans\Plan; -use App\Models\Notes\Note; use App\Models\Objects\Field; use App\Models\Objects\FieldsGroup; use App\Models\Objects\NirObject; use App\Models\Objects\ObjectType; +use App\Models\Pages\Page; use App\Models\Permission; -use App\Models\Polls\Poll; -use App\Models\Polls\PollInvitation; -use App\Models\Processes\Demand; -use App\Models\Processes\Participant; -use App\Models\Processes\Performer; -use App\Models\Processes\Process; -use App\Models\Processes\Scenario; -use App\Models\Processes\Stage; -use App\Models\Processes\Task; use App\Models\Role; use App\Models\SocialProvider; use App\Models\User; -use App\Models\UserKey; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Mail; @@ -82,7 +53,9 @@ class AppServiceProvider extends ServiceProvider 'object-field' => Field::class, 'fields-group' => FieldsGroup::class, 'object' => NirObject::class, - 'object-type' => ObjectType::class + 'object-type' => ObjectType::class, + + 'page' => Page::class ]); } } diff --git a/app/Support/HasObjectsTrait.php b/app/Support/HasObjectsTrait.php index 0965626..21b1b99 100644 --- a/app/Support/HasObjectsTrait.php +++ b/app/Support/HasObjectsTrait.php @@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany; trait HasObjectsTrait { public function objects(): MorphToMany { - return $this->morphToMany(NirObject::class, 'objectable')->withTimestamps(); + return $this->morphToMany(NirObject::class, 'objectable')->orderByPivot('ord')->withTimestamps(); } public function getObjectAttribute() { @@ -21,8 +21,13 @@ trait HasObjectsTrait { return ($type = ObjectType::query()->where(['name' => $typeName])->first()) ? $this->objects()->firstOrCreate(['type_id' => $type->id]) : null; } - public function createObject($typeName): ?Model { - return ($type = ObjectType::query()->where(['name' => $typeName])->first()) ? $this->objects()->create(['type_id' => $type->id]) : null; + public function createObject($typeName, $ord = null): ?Model { + if (($type = ObjectType::query()->where(['name' => $typeName])->first()) && ($object = NirObject::create(['type_id' => $type->id]))) { + if ($ord !== null) $ord = ($res = $this->objects()->where(['type_id' => $type->id])->withPivot('ord')->reorder()->orderByPivot('ord', 'desc')->first()) ? ($res->pivot->ord + 1) : 0; + $this->objects()->attach($object->id, ['ord' => $ord]); + return $object; + } + return null; } public function getValue($fieldName) { diff --git a/app/Transformers/Pages/PageTransformer.php b/app/Transformers/Pages/PageTransformer.php new file mode 100644 index 0000000..8770770 --- /dev/null +++ b/app/Transformers/Pages/PageTransformer.php @@ -0,0 +1,57 @@ + $model->uuid, + 'slug' => $model->slug, + 'link' => $model->link, + 'type' => $model->parsedType, + 'name' => $model->name, + 'title' => $model->title, + 'h1' => $model->h1, + 'created_at' => $model->created_at ? $model->created_at->toIso8601String() : null, + 'updated_at' => $model->updated_at ? $model->updated_at->toIso8601String() : null + ]; + } + + public function includeChildren(Page $model): Collection { + return $this->collection($model->children, new PageTransformer()); + } + + public function includeParent(Page $model): ?Item { + return $model->parent ? $this->item($model->parent, new PageTransformer()) : null; + } + + public function includeSections(Page $model): Collection { + return $this->collection($model->sections, new ObjectTransformer()); + } + + public function includeSidebars(Page $model): Collection { + return $this->collection($model->sidebars, new ObjectTransformer()); + } + + public function includePermissions(Page $model): Primitive { + return $this->primitive((new PermissionsService($model))->get()); + } + + +} diff --git a/database/migrations/2022_09_05_212157_create_objectables_table.php b/database/migrations/2022_09_05_212157_create_objectables_table.php index 12772d4..5634a7c 100644 --- a/database/migrations/2022_09_05_212157_create_objectables_table.php +++ b/database/migrations/2022_09_05_212157_create_objectables_table.php @@ -17,6 +17,7 @@ class CreateObjectablesTable extends Migration $table->id(); $table->integer('nir_object_id')->index()->nullable(); $table->nullableMorphs('objectable'); + $table->integer('ord')->index()->default(0); $table->timestamps(); }); } diff --git a/database/migrations/2023_05_29_183212_create_pages_table.php b/database/migrations/2023_05_29_183212_create_pages_table.php new file mode 100644 index 0000000..bcb0936 --- /dev/null +++ b/database/migrations/2023_05_29_183212_create_pages_table.php @@ -0,0 +1,40 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('parent_id')->index()->default(0); + $table->string('slug')->index()->nullable(); + $table->string('type')->index()->nullable(); + $table->string('name')->index()->nullable(); + $table->string('title')->index()->nullable(); + $table->string('h1')->index()->nullable(); + $table->integer('ord')->index()->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('pages'); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 03c30f5..9c0e792 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -4,6 +4,7 @@ namespace Database\Seeders; use Database\Seeders\Dictionaries\DictionariesTablesSeeder; use Database\Seeders\Objects\ObjectsTablesSeeder; +use Database\Seeders\Pages\PagesTableSeeder; use Database\Seeders\Users\RoleTableSeeder; use Database\Seeders\Users\UsersTableSeeder; @@ -15,5 +16,6 @@ class DatabaseSeeder extends Seeder { $this->call(UsersTableSeeder::class); $this->call(ObjectsTablesSeeder::class); $this->call(DictionariesTablesSeeder::class); + $this->call(PagesTableSeeder::class); } } diff --git a/database/seeders/Dictionaries/DictionariesTableSeeder.php b/database/seeders/Dictionaries/DictionariesTableSeeder.php index 87d6863..20dac8d 100644 --- a/database/seeders/Dictionaries/DictionariesTableSeeder.php +++ b/database/seeders/Dictionaries/DictionariesTableSeeder.php @@ -7,6 +7,10 @@ use Illuminate\Database\Seeder; class DictionariesTableSeeder extends Seeder { public array $dictionaries = [ + 'list-types' => [ + 'title' => 'Виды списка', + 'items' => ['marked' => 'Маркированный', 'numeric' => 'Нумерованный'] + ] ]; public function run() { diff --git a/database/seeders/Objects/FieldsTableSeeder.php b/database/seeders/Objects/FieldsTableSeeder.php index 080c8d1..eba10f3 100644 --- a/database/seeders/Objects/FieldsTableSeeder.php +++ b/database/seeders/Objects/FieldsTableSeeder.php @@ -2,12 +2,78 @@ namespace Database\Seeders\Objects; +use App\Models\Dictionaries\DictionaryItem; use App\Models\Objects\Field; +use App\Models\Objects\FieldType; +use App\Transformers\Dictionaries\DictionaryItemTransformer; use Illuminate\Database\Seeder; class FieldsTableSeeder extends Seeder { public array $fields = [ + 'header' => [ + 'title' => 'Текст заголовка', + 'type' => FieldType::TEXT + ], + 'header-required' => [ + 'title' => 'Текст заголовка', + 'type' => FieldType::TEXT, + 'required' => true + ], + 'subheader' => [ + 'title' => 'Текст подзаголовка', + 'type' => FieldType::TEXT + ], + 'subheader-required' => [ + 'title' => 'Текст подзаголовка', + 'type' => FieldType::TEXT, + 'required' => true + ], + + 'documents' => [ + 'title' => 'Документы', + 'type' => FieldType::DOCUMENT, + 'multiple' => true + ], + 'documents-required' => [ + 'title' => 'Документы', + 'type' => FieldType::DOCUMENT, + 'multiple' => true, + 'required' => true + ], + + 'text' => [ + 'title' => 'Содержимое текстового блока', + 'type' => FieldType::TEXT + ], + 'text-required' => [ + 'title' => 'Содержимое текстового блока', + 'type' => FieldType::TEXT, + 'required' => true + ], + + 'list-type' => [ + 'title' => 'Вид списка', + 'type' => FieldType::RELATION, + 'required' => true, + 'params' => [ + 'related' => DictionaryItem::class, 'transformer' => DictionaryItemTransformer::class, + 'options' => ['show' => true, 'whereHas' => ['dictionary' => ['name' => 'list-types']]] + ] + ], + 'list-items' => [ + 'title' => 'Элементы списка', + 'type' => FieldType::TEXT, + 'multiple' => true, + 'required' => true + ], + + 'images' => [ + 'title' => 'Изображения', + 'type' => FieldType::IMAGE, + 'multiple' => true, + 'required' => true + ] ]; public function run() { diff --git a/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php b/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php index 1c20b24..5b3e919 100644 --- a/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php +++ b/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php @@ -9,6 +9,41 @@ use Illuminate\Database\Seeder; class ObjectTypeFieldsTableSeeder extends Seeder { public array $objectTypeFields = [ + 'page-sidebar' => [ + 'common' => [ + 'fields' => ['header', 'subheader', 'documents'] + ] + ], + 'page-section-header' => [ + 'common' => [ + 'fields' => ['header-required'] + ] + ], + 'page-section-subheader' => [ + 'common' => [ + 'fields' => ['subheader-required'] + ] + ], + 'page-section-text' => [ + 'common' => [ + 'fields' => ['text-required'] + ] + ], + 'page-section-list' => [ + 'common' => [ + 'fields' => ['list-type', 'list-items'] + ] + ], + 'page-section-images' => [ + 'common' => [ + 'fields' => ['images'] + ] + ], + 'page-section-videos' => [ + 'common' => [ + 'fields' => [] + ] + ] ]; diff --git a/database/seeders/Objects/ObjectTypesTableSeeder.php b/database/seeders/Objects/ObjectTypesTableSeeder.php index 04b81b0..1321e3b 100644 --- a/database/seeders/Objects/ObjectTypesTableSeeder.php +++ b/database/seeders/Objects/ObjectTypesTableSeeder.php @@ -7,7 +7,32 @@ use Illuminate\Database\Seeder; class ObjectTypesTableSeeder extends Seeder { public array $types = [ - + 'page-sidebar' => [ + 'title' => 'Сторонний блок контентной страницы' + ], + 'page-section' => [ + 'title' => 'Секция контентной страницы', + 'children' => [ + 'page-section-header' => [ + 'title' => 'Заголовок' + ], + 'page-section-subheader' => [ + 'title' => 'Подзаголовок' + ], + 'page-section-text' => [ + 'title' => 'Текст' + ], + 'page-section-list' => [ + 'title' => 'Список' + ], + 'page-section-images' => [ + 'title' => 'Изображения' + ], + 'page-section-videos' => [ + 'title' => 'Видео' + ] + ] + ] ]; public function run() { diff --git a/database/seeders/Pages/PagesTableSeeder.php b/database/seeders/Pages/PagesTableSeeder.php new file mode 100644 index 0000000..e6b8e01 --- /dev/null +++ b/database/seeders/Pages/PagesTableSeeder.php @@ -0,0 +1,90 @@ + [ + 'children' => [ + 'Руководство' => [ + + ], + 'Документы' => [ + 'children' => [ + 'Документы об учреждении' => [], + 'Закупки' => [], + 'Бухгалтерская отчетность' => [], + 'Государственное задание' => [], + 'Нормативные правовые акты' => [], + 'Антимонопольное законодательство' => [], + 'Специальная оценка условий труда' => [] + ] + ], + 'Структура' => [ + + ], + 'Наблюдательный совет' => [ + 'children' => [ + 'Структура' => [], + 'Документы' => [], + 'Решения' => [] + ] + ], + 'Закупки' => [ + + ], + 'Противодействие коррупции' => [ + 'children' => [ + 'ФЗ, указы, постановления' => [], + 'Ведомственные нормативные правовые акты' => [], + 'Внутренние нормативные документы' => [], + 'Антикоррупционная экспертиза' => [], + 'Методические материалы' => [], + 'Формы документов для заполнения' => [], + 'Финансовые сведения' => [], + 'Aттестационная комиссия' => [], + 'Обратная связь' => [], + 'Остальные документы' => [] + ] + ] + ] + ], + 'Деятельность' => [ + + ], + 'Коммерческие услуги' => [ + + ], + 'Пресс-центр' => [ + + ], + 'Контакты' => [ + + ] + ]; + + public function run() { + $ord = 0; + collect($this->pages)->each(function($data, $name) use(&$ord) { + $data['ord'] = $ord++; + $this->importPage($name, $data); + }); + } + + public function importPage($name, $data, ?Page $parent = null) { + $slug = Str::slug(Str::transliterate($name)); + $page = Page::firstOrCreate(['parent_id' => $parent->id ?? 0, 'slug' => $slug]); + $page->update(['name' => $name]); + if ($v = collect($data)->except('children')->all()) $page->update($v); + $ord = 0; + collect($data['children'] ?? [])->each(function($data, $name) use($page, &$ord) { + $data['ord'] = $ord++; + $this->importPage($name, $data, $page); + }); + } + +} diff --git a/database/seeders/Pages/PagesTablesSeeder.php b/database/seeders/Pages/PagesTablesSeeder.php new file mode 100644 index 0000000..88106c6 --- /dev/null +++ b/database/seeders/Pages/PagesTablesSeeder.php @@ -0,0 +1,11 @@ +call(PagesTableSeeder::class); + } +} diff --git a/routes/api.php b/routes/api.php index 5ee0f98..98e4f54 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,6 +14,10 @@ Route::put('passwords/reset', 'Api\Auth\PasswordsController@update'); Route::get('/check-email', 'Api\Auth\RegisterController@checkEmail'); +Route::get('pages', 'Api\Pages\PagesController@index'); +Route::get('pages/root', 'Api\Pages\PagesController@root'); +Route::get('pages/{id}', 'Api\Pages\PagesController@show'); + Route::group(['middleware' => ['auth:api']], function() { Route::apiResource('users', 'Api\Users\UsersController'); Route::apiResource('roles', 'Api\Users\RolesController');