├── .gitignore ├── LICENSE ├── README.md ├── changelog.md ├── composer.json ├── img └── laravel-pagebuilder.png └── src ├── Pagebuilder ├── Commands │ ├── ControllerCommand.php │ ├── InstallCommand.php │ ├── ModelCommand.php │ └── ViewCommand.php ├── Contracts │ ├── ElementContract.php │ ├── LanguageContract.php │ ├── PagebuilderContract.php │ └── RowColumnContract.php ├── Controllers │ ├── ElementTypeController.php │ ├── LanguageController.php │ ├── PagebuilderController.php │ └── UploadController.php ├── Database │ └── Seeds │ │ ├── ElementTableSeeder.php │ │ └── LanguageTableSeeder.php ├── Elements.php ├── Exceptions │ └── MissingTranslationsException.php ├── Languages.php ├── Livewire │ ├── DatePicker.php │ └── Settings.php ├── Models │ ├── BasePage.php │ ├── Column.php │ ├── ColumnTranslation.php │ ├── ElementType.php │ ├── Language.php │ ├── Row.php │ └── Translation.php ├── Pagebuilder.php ├── PagebuilderServiceProvider.php ├── RowColumn.php ├── Translations │ └── Translatable.php └── Uploads │ └── Uploadable.php ├── config └── pagebuilder.php ├── database └── migrations │ ├── 2018_05_11_125042_create_languages_table.php │ ├── 2018_05_11_133201_create_element_types_table.php │ ├── 2018_09_20_065609_create_pages_table.php │ ├── 2018_09_20_065917_create_rows_table.php │ ├── 2018_09_20_070220_create_columns_table.php │ ├── 2018_09_20_082538_create_column_translations_table.php │ ├── 2018_09_20_084930_create_translations_table.php │ └── 2018_09_26_132707_create_media_table.php ├── img └── pagebuilder │ └── icons │ ├── grid-12.png │ ├── grid12.png │ └── grid6-6.png ├── resources ├── lang │ ├── ar │ │ └── crud.php │ ├── de │ │ └── crud.php │ └── en │ │ └── crud.php ├── stubs │ ├── controllers │ │ └── page_controller.stub │ ├── models │ │ └── page.stub │ └── views │ │ └── pages │ │ ├── create.stub │ │ ├── edit.stub │ │ └── index.stub └── views │ ├── element-types │ ├── create.blade.php │ ├── edit.blade.php │ └── index.blade.php │ ├── languages │ ├── create.blade.php │ ├── edit.blade.php │ └── index.blade.php │ ├── livewire │ ├── date-picker.blade.php │ └── settings.blade.php │ ├── main.blade.php │ └── notifications.blade.php └── routes └── web.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock 3 | coverage/ 4 | /nbproject/private/ 5 | /nbproject 6 | .idea 7 | /node_modules/ 8 | /.vscode 9 | .push.settings.jsonc 10 | .history 11 | .vscode 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Alexej Krzewitzki alexej@helloo.it 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel-Pagebuilder 2 | 3 | ![Laravel Pagebuilder](img/laravel-pagebuilder.png) 4 | 5 | ### Docs 6 | 7 | - [Installation](#installation) 8 | - [Configuration](#configuration) 9 | - [Migrations](#migrations) 10 | - [Seeds](#seeds) 11 | - [Generators](#generators) 12 | - [Slugs](#slugs) 13 | - [Fields](#fields) 14 | - [JS](#js-components) 15 | - [Laravel compatibility](#laravel-compatibility) 16 | 17 | ## Installation 18 | 19 | #### Install the package 20 | 21 | ```bash 22 | composer require flobbos/laravel-pagebuilder 23 | ``` 24 | 25 | #### Install pagebuilder 26 | 27 | Laravel 5.7+ 28 | 29 | ```bash 30 | php artisan pagebuilder:install 31 | ``` 32 | 33 | This will run all migrations and trigger the seeder for the initial elements 34 | and a language entry 35 | 36 | ## Configuration 37 | 38 | The only thing in the config file is the classes you wish to use with Pagebuilder. 39 | 40 | You need to generate a model class first using the built in generator. 41 | 42 | ```php 43 | 'builder_classes' => [ 44 | 'page' => App\Page::class, 45 | ] 46 | ``` 47 | 48 | Set additional classes that are supposed to run in a Pagebuilder controller. You can 49 | generate multiple controllers for multiple resources using the Pagebuilder. 50 | 51 | ```php 52 | $this->articles->setClass('page'); 53 | ``` 54 | 55 | This setting in the generated controller will tell it which resource it needs to 56 | use for generating content. 57 | 58 | ## Generators 59 | 60 | You can generate the controller and views for creating pagebuilder based resources 61 | using the following generator commands: 62 | 63 | ```php 64 | php artisan pagebuilder:controller ArticleController --route=pagebuilder.pages --views=pagebuilder.pages 65 | ``` 66 | 67 | This will generate a complete resource controller named PageController where the routes 68 | and view calls are replaced with the values above. The views will always be prefixed with 69 | vendor. 70 | 71 | ```php 72 | php artisan pagebuilder:views pagebuilder.pages --route=pagebuilder.pages 73 | ``` 74 | 75 | Use the corresponding routes that you set with the controller and it will all work magically. 76 | 77 | ```php 78 | pagebuilder:model Page 79 | ``` 80 | 81 | This will generate a Page model that extends the BasePage model that comes with 82 | the package so all necessary relationships and translation options are included. 83 | This step is necessary to be able to generate content because the BasePage model 84 | should not be used as a resource directly. 85 | 86 | ## Slugs 87 | 88 | The pagebuilder is capable of generating translated URL slugs for you. All you 89 | need to do is uncomment the following line from your generated model: 90 | 91 | ```php 92 | //protected $slug_field = 'title'; 93 | ``` 94 | 95 | This will tell the pagebuilder which field in the translations is supposed to 96 | generate the URL slug. The slug will automatically be regenerated when you change 97 | the named field. 98 | 99 | ## Fields 100 | 101 | There are some basic fields in the settings area for an resource but you are free 102 | to add as many additional fields as needed. These fields will be automatically 103 | saved in the database without further modifications to the DB structure. 104 | 105 | ## JS Components 106 | 107 | To use the pagebuilder you need to install its VueJS counterpart by running: 108 | 109 | ```bash 110 | npm install @chrisbielak/vue-pagebuilder 111 | ``` 112 | 113 | All the needed documentation can be found here: 114 | [Vue Pagebuilder](https://www.npmjs.com/package/@chrisbielak/vue-pagebuilder "Google's Homepage") 115 | 116 | ## Laravel compatibility 117 | 118 | | Laravel | Crudable | 119 | | :------ | :------- | 120 | | 9.x | >2.0.0 | 121 | | 8.x | >1.0.10 | 122 | | 7.x | >1.0.10 | 123 | | 6.x | >1.0.3 | 124 | | 5.8 | >1.0.0 | 125 | | 5.7 | >1.0.0 | 126 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## Version History 2 | 3 | ### v. 2.0.0 4 | 5 | - First release for Laravel 8 and Livewire 6 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flobbos/laravel-pagebuilder", 3 | "description": "Build content in your database with translations.", 4 | "keywords": [ 5 | "laravel", 6 | "pages", 7 | "database" 8 | ], 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Alexej Krzewitzki", 13 | "email": "alexej@helloo.it", 14 | "homepage": "http://helloo.it" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.0|^8.1", 19 | "illuminate/support": "9.*|10.*", 20 | "flobbos/laravel-translatable-db": "^1.4", 21 | "cocur/slugify": "^4.0", 22 | "livewire/livewire": "^2.4" 23 | }, 24 | "extra": { 25 | "laravel": { 26 | "providers": [ 27 | "Flobbos\\Pagebuilder\\PagebuilderServiceProvider" 28 | ] 29 | } 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Flobbos\\Pagebuilder\\": [ 34 | "src/Pagebuilder" 35 | ] 36 | }, 37 | "classmap": [] 38 | }, 39 | "minimum-stability": "stable" 40 | } -------------------------------------------------------------------------------- /img/laravel-pagebuilder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flobbos/laravel-pagebuilder/a5bf99ec9c6e36cf1bd28a3a25de8c69c7a0db82/img/laravel-pagebuilder.png -------------------------------------------------------------------------------- /src/Pagebuilder/Commands/ControllerCommand.php: -------------------------------------------------------------------------------- 1 | option('views'); 43 | } 44 | 45 | protected function replaceDummyRoute() 46 | { 47 | return $this->option('route'); 48 | } 49 | 50 | protected function replaceDummySetClass() 51 | { 52 | return Str::singular(strtolower(str_replace('Controller', '', $this->getNameInput()))); 53 | } 54 | 55 | protected function replaceDummyVariable() 56 | { 57 | return Str::singular(strtolower(str_replace('Controller', '', $this->getNameInput()))); 58 | } 59 | 60 | /** 61 | * Build the class with the given name. 62 | * 63 | * Remove the base controller import if we are already in base namespace. 64 | * 65 | * @param string $name 66 | * @return string 67 | */ 68 | protected function buildClass($name) 69 | { 70 | $controllerNamespace = $this->getNamespace($name); 71 | 72 | $replace["use {$controllerNamespace}\Controller;\n"] = ''; 73 | $replace = array_merge($replace, [ 74 | 'DummyViewPath' => $this->replaceViewPath(), 75 | 'DummyRoute' => $this->replaceDummyRoute(), 76 | 'DummySetClass' => $this->replaceDummySetClass(), 77 | 'DummyVariable' => $this->replaceDummyVariable(), 78 | ]); 79 | //dd($replace); 80 | return str_replace( 81 | array_keys($replace), 82 | array_values($replace), 83 | parent::buildClass($name) 84 | ); 85 | } 86 | 87 | /** 88 | * Get the stub file for the generator. 89 | * 90 | * @return string 91 | */ 92 | protected function getStub() 93 | { 94 | return __DIR__ . '/../../resources/stubs/controllers/page_controller.stub'; 95 | } 96 | 97 | /** 98 | * Execute the console command. 99 | * 100 | * @return mixed 101 | */ 102 | public function handle() 103 | { 104 | $this->comment('Building pagebuilder resource controller'); 105 | 106 | $name = $this->qualifyClass($this->getNameInput()); 107 | $path = $this->getPath($name); 108 | if ($this->alreadyExists($this->getNameInput())) { 109 | $this->error($this->type . ' already exists!'); 110 | return false; 111 | } 112 | 113 | // Next, we will generate the path to the location where this class' file should get 114 | // written. Then, we will build the class and make the proper replacements on the 115 | // stub files so that it gets the correctly formatted namespace and class name. 116 | $this->makeDirectory($path); 117 | $this->files->put($path, $this->buildClass($name)); 118 | 119 | $this->info($this->type . ' created successfully.'); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Pagebuilder/Commands/InstallCommand.php: -------------------------------------------------------------------------------- 1 | comment('Running migrations.'); 38 | 39 | Artisan::call('migrate'); 40 | 41 | $this->comment('Running seeds.'); 42 | Artisan::call('db:seed', ['--class' => 'Flobbos\\Pagebuilder\\ElementTableSeeder']); 43 | Artisan::call('db:seed', ['--class' => 'Flobbos\\Pagebuilder\\LanguageTableSeeder']); 44 | 45 | $this->comment('Publishing package files'); 46 | 47 | Artisan::call('vendor:publish', ['--provider' => 'Flobbos\\Pagebuilder\\PagebuilderServiceProvider']); 48 | 49 | $this->info('Installation completed.'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Pagebuilder/Commands/ModelCommand.php: -------------------------------------------------------------------------------- 1 | getNamespace($name) . '\\', '', $name); 43 | return Str::plural(strtolower(Str::snake($class))); 44 | } 45 | 46 | protected function replaceDummyClass($name) 47 | { 48 | return str_replace($this->getNamespace($name) . '\\', '', $name); 49 | } 50 | 51 | /** 52 | * Build the class with the given name. 53 | * 54 | * Remove the base controller import if we are already in base namespace. 55 | * 56 | * @param string $name 57 | * @return string 58 | */ 59 | protected function buildClass($name) 60 | { 61 | 62 | $replace = [ 63 | 'DummyClass' => $this->replaceDummyClass($name), 64 | 'DummyTable' => $this->replaceDummyTable($name) 65 | ]; 66 | //dd($replace); 67 | return str_replace( 68 | array_keys($replace), 69 | array_values($replace), 70 | parent::buildClass($name) 71 | ); 72 | } 73 | 74 | /** 75 | * Get the stub file for the generator. 76 | * 77 | * @return string 78 | */ 79 | protected function getStub() 80 | { 81 | return __DIR__ . '/../../resources/stubs/models/page.stub'; 82 | } 83 | 84 | /** 85 | * Execute the console command. 86 | * 87 | * @return mixed 88 | */ 89 | public function handle() 90 | { 91 | $this->comment('Building pagebuilder model'); 92 | $name = $this->qualifyClass($this->getNameInput()); 93 | $path = $this->getPath($name); 94 | if ($this->alreadyExists($this->getNameInput())) { 95 | $this->error($this->type . ' already exists!'); 96 | return false; 97 | } 98 | 99 | // Next, we will generate the path to the location where this class' file should get 100 | // written. Then, we will build the class and make the proper replacements on the 101 | // stub files so that it gets the correctly formatted namespace and class name. 102 | $this->makeDirectory($path); 103 | $this->files->put($path, $this->buildClass($name)); 104 | 105 | $this->info($this->type . ' created successfully.'); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Pagebuilder/Commands/ViewCommand.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/../../resources/stubs/views/pages/index.stub', 39 | 'create.blade.php' => __DIR__ . '/../../resources/stubs/views/pages/create.stub', 40 | 'edit.blade.php' => __DIR__ . '/../../resources/stubs/views/pages/edit.stub' 41 | ]; 42 | } 43 | 44 | protected function getPathInput() 45 | { 46 | return trim($this->argument('path')); 47 | } 48 | 49 | /** 50 | * Get the destination class path. 51 | * 52 | * @param string $name 53 | * @return string 54 | */ 55 | protected function getPath($name) 56 | { 57 | return resource_path('views/vendor/' . $this->getDirectoryName($name)); 58 | } 59 | 60 | protected function getDirectoryName($name) 61 | { 62 | return Str::plural(strtolower(Str::kebab(str_replace('.', '/', $name)))); 63 | } 64 | 65 | /** 66 | * Replace the service variable in the stub using pluralization 67 | * 68 | * @param string $stub 69 | * @param string $name 70 | * @return string 71 | */ 72 | protected function replaceDummyRoute($name) 73 | { 74 | return $this->option('route'); 75 | } 76 | 77 | protected function replaceViewPath($name) 78 | { 79 | return str_replace('/', '.', $this->argument('path')); 80 | } 81 | 82 | /** 83 | * Build the class with the given name. 84 | * 85 | * Remove the base controller import if we are already in base namespace. 86 | * 87 | * @param string $name 88 | * @return string 89 | */ 90 | protected function buildClass($name) 91 | { 92 | $controllerNamespace = $this->getNamespace($name); 93 | $replace = [ 94 | 'DummyViewPath' => $this->replaceViewPath($name), 95 | 'DummyRoute' => $this->replaceDummyRoute($name) 96 | ]; 97 | return str_replace( 98 | array_keys($replace), 99 | array_values($replace), 100 | $this->generateClass($name) 101 | ); 102 | } 103 | 104 | protected function generateClass($name) 105 | { 106 | $stub = $this->files->get($this->current_stub); 107 | return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name); 108 | } 109 | 110 | /** 111 | * Determine if the class already exists. 112 | * 113 | * @param string $rawName 114 | * @return bool 115 | */ 116 | protected function alreadyExists($rawName) 117 | { 118 | return $this->files->exists($this->getPath($this->getPathInput())); 119 | } 120 | 121 | /** 122 | * Execute the console command. 123 | * 124 | * @return mixed 125 | */ 126 | public function handle() 127 | { 128 | $this->comment('Building new resource views.'); 129 | 130 | $path = $this->getPath(strtolower(Str::kebab($this->getPathInput()))); 131 | if ($this->alreadyExists($this->getPathInput())) { 132 | $this->error($this->type . ' already exists!'); 133 | return false; 134 | } 135 | 136 | // Next, we will generate the path to the location where this class' file should get 137 | // written. Then, we will build the class and make the proper replacements on the 138 | // stub files so that it gets the correctly formatted namespace and class name. 139 | foreach ($this->getStub() as $name => $stub) { 140 | $this->current_stub = $stub; 141 | $this->makeDirectory($path . '/' . $name); 142 | $this->files->put($path . '/' . $name, $this->buildClass($this->getPathInput())); 143 | } 144 | $this->info($this->type . ' created successfully.'); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Pagebuilder/Contracts/ElementContract.php: -------------------------------------------------------------------------------- 1 | element_types = $element_types; 18 | } 19 | 20 | /** 21 | * Display a listing of the resource. 22 | * 23 | * @return \Illuminate\Http\Response 24 | */ 25 | public function index() 26 | { 27 | return view('pagebuilder::element-types.index')->with(['element_types' => $this->element_types->get()]); 28 | } 29 | 30 | /** 31 | * Show the form for creating a new resource. 32 | * 33 | * @return \Illuminate\Http\Response 34 | */ 35 | public function create() 36 | { 37 | return view('pagebuilder::element-types.create'); 38 | } 39 | 40 | /** 41 | * Store a newly created resource in storage. 42 | * 43 | * @param \Illuminate\Http\Request $request 44 | * @return \Illuminate\Http\Response 45 | */ 46 | public function store(Request $request) 47 | { 48 | $this->validate($request, []); 49 | 50 | try { 51 | $this->element_types->create($request->all()); 52 | return redirect()->route('pagebuilder::element-types.index')->withMessage(trans('pagebuilder::crud.record_created')); 53 | } catch (Exception $ex) { 54 | return redirect()->back()->withErrors($ex->getMessage())->withInput(); 55 | } 56 | } 57 | 58 | /** 59 | * Show the form for editing the specified resource. 60 | * 61 | * @param int $id 62 | * @return \Illuminate\Http\Response 63 | */ 64 | public function edit($id) 65 | { 66 | return view('pagebuilder::element-types.edit')->with(['element_type' => $this->element_types->find($id)]); 67 | } 68 | 69 | /** 70 | * Update the specified resource in storage. 71 | * 72 | * @param \Illuminate\Http\Request $request 73 | * @param int $id 74 | * @return \Illuminate\Http\Response 75 | */ 76 | public function update(Request $request, $id) 77 | { 78 | $this->validate($request, []); 79 | 80 | try { 81 | $this->element_types->update($id, $request->all()); 82 | return redirect()->route('pagebuilder::element-types.index')->withMessage(trans('pagebuilder::crud.record_updated')); 83 | } catch (Exception $ex) { 84 | return redirect()->back()->withInput()->withErrors($ex->getMessage()); 85 | } 86 | } 87 | 88 | /** 89 | * Remove the specified resource from storage. 90 | * 91 | * @param int $id 92 | * @return \Illuminate\Http\Response 93 | */ 94 | public function destroy($id) 95 | { 96 | try { 97 | $this->element_types->delete($id); 98 | return redirect()->route('pagebuilder::element-types.index')->withMessage(trans('pagebuilder::crud.record_deleted')); 99 | } catch (Exception $ex) { 100 | return redirect()->route('pagebuilder::element-types.index')->withErrors($ex->getMessage()); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Pagebuilder/Controllers/LanguageController.php: -------------------------------------------------------------------------------- 1 | language = $language; 18 | } 19 | 20 | /** 21 | * Display a listing of the resource. 22 | * 23 | * @return \Illuminate\Http\Response 24 | */ 25 | public function index() 26 | { 27 | return view('pagebuilder::languages.index')->with(['languages' => $this->language->get()]); 28 | } 29 | 30 | /** 31 | * Show the form for creating a new resource. 32 | * 33 | * @return \Illuminate\Http\Response 34 | */ 35 | public function create() 36 | { 37 | return view('pagebuilder::languages.create'); 38 | } 39 | 40 | /** 41 | * Store a newly created resource in storage. 42 | * 43 | * @param \Illuminate\Http\Request $request 44 | * @return \Illuminate\Http\Response 45 | */ 46 | public function store(Request $request) 47 | { 48 | $this->validate($request, []); 49 | 50 | try { 51 | $this->language->create($request->all()); 52 | return redirect()->route('pagebuilder::languages.index')->withMessage(trans('pagebuilder::crud.record_created')); 53 | } catch (Exception $ex) { 54 | return redirect()->back()->withErrors($ex->getMessage())->withInput(); 55 | } 56 | } 57 | 58 | /** 59 | * Display the specified resource. 60 | * 61 | * @param int $id 62 | * @return \Illuminate\Http\Response 63 | */ 64 | public function show($id) 65 | { 66 | return view('pagebuilder::languages.show')->with(['language' => $this->language->find($id)]); 67 | } 68 | 69 | /** 70 | * Show the form for editing the specified resource. 71 | * 72 | * @param int $id 73 | * @return \Illuminate\Http\Response 74 | */ 75 | public function edit($id) 76 | { 77 | return view('pagebuilder::languages.edit')->with(['language' => $this->language->find($id)]); 78 | } 79 | 80 | /** 81 | * Update the specified resource in storage. 82 | * 83 | * @param \Illuminate\Http\Request $request 84 | * @param int $id 85 | * @return \Illuminate\Http\Response 86 | */ 87 | public function update(Request $request, $id) 88 | { 89 | $this->validate($request, []); 90 | 91 | try { 92 | $this->language->update($id, $request->all()); 93 | return redirect()->route('pagebuilder::languages.index')->withMessage(trans('pagebuilder::crud.record_updated')); 94 | } catch (Exception $ex) { 95 | return redirect()->back()->withInput()->withErrors($ex->getMessage()); 96 | } 97 | } 98 | 99 | /** 100 | * Remove the specified resource from storage. 101 | * 102 | * @param int $id 103 | * @return \Illuminate\Http\Response 104 | */ 105 | public function destroy($id) 106 | { 107 | try { 108 | $this->language->delete($id); 109 | return redirect()->route('pagebuilder::languages.index')->withMessage(trans('pagebuilder::crud.record_deleted')); 110 | } catch (Exception $ex) { 111 | return redirect()->route('pagebuilder::languages.index')->withErrors($ex->getMessage()); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Pagebuilder/Controllers/PagebuilderController.php: -------------------------------------------------------------------------------- 1 | with([ 18 | 'elements' => $elements->get(), 19 | 'languages' => $lang->get() 20 | ]); 21 | } 22 | 23 | /** 24 | * 25 | * @param Request $request 26 | * @return type 27 | */ 28 | public function deleteRow(Request $request, RowColumnContract $rows) 29 | { 30 | try { 31 | $rows->deleteRow($request->get('id')); 32 | return response()->json(['success' => true], 200); 33 | } catch (Exception $ex) { 34 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422); 35 | } 36 | } 37 | 38 | /** 39 | * 40 | * @param Request $request 41 | * @return type 42 | */ 43 | public function deleteColumn(Request $request, RowColumnContract $rows) 44 | { 45 | try { 46 | $rows->deleteColumn($request->get('id')); 47 | return response()->json(['success' => true], 200); 48 | } catch (Exception $ex) { 49 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Pagebuilder/Controllers/UploadController.php: -------------------------------------------------------------------------------- 1 | hasFile('photo')) { 24 | return response()->json([ 25 | 'filename' => $this->handleUpload($request, 'photo'), 26 | 'column_id' => $request->get('column_id'), 27 | 'lang_id' => $request->get('lang_id') 28 | ], 200); 29 | } 30 | if ($request->hasFile('file')) { 31 | return response()->json([ 32 | 'filename' => $this->handleUpload($request, 'file', 'files'), 33 | 'column_id' => $request->get('column_id'), 34 | 'lang_id' => $request->get('lang_id') 35 | ], 200); 36 | } 37 | throw new Exception('No file uploaded'); 38 | } catch (Exception $ex) { 39 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422); 40 | } 41 | } 42 | 43 | /** 44 | * Remove the specified resource from storage. 45 | * 46 | * @param int $id 47 | * @return \Illuminate\Http\Response 48 | */ 49 | public function destroy(Request $request) 50 | { 51 | try { 52 | if ($request->has('delete_photo')) { 53 | Storage::disk($request->get('storage'))->delete($request->get('delete_photo')); 54 | } 55 | return response()->json(['success' => true], 200); 56 | } catch (Exception $ex) { 57 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Pagebuilder/Database/Seeds/ElementTableSeeder.php: -------------------------------------------------------------------------------- 1 | insert([ 19 | 'name' => 'Headline + Text', 20 | 'component' => 'v-headline-text', 21 | 'icon' => 'headline-text-element-icon', 22 | 'sorting' => 1 23 | ]); 24 | //Text component 25 | DB::table('element_types')->insert([ 26 | 'name' => 'Text', 27 | 'component' => 'v-text', 28 | 'icon' => 'text-element-icon', 29 | 'sorting' => 2 30 | ]); 31 | //Photo + Description 32 | DB::table('element_types')->insert([ 33 | 'name' => 'Photo + Description', 34 | 'component' => 'v-photo-description', 35 | 'icon' => 'image-element-icon', 36 | 'sorting' => 3 37 | ]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Pagebuilder/Database/Seeds/LanguageTableSeeder.php: -------------------------------------------------------------------------------- 1 | insert([ 19 | 'name' => 'Deutsch', 20 | 'locale' => 'de', 21 | ]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Pagebuilder/Elements.php: -------------------------------------------------------------------------------- 1 | model = $element_type; 17 | } 18 | 19 | public function get() 20 | { 21 | return $this->model->get(); 22 | } 23 | 24 | public function find($id) 25 | { 26 | return $this->model->find($id); 27 | } 28 | 29 | public function create(array $element_data) 30 | { 31 | return $this->model->create($element_data); 32 | } 33 | 34 | public function update($id, array $element_data) 35 | { 36 | $element = $this->find($id); 37 | if (is_null($element)) { 38 | throw new Exception('Model not found'); 39 | } 40 | if ($element->update($element_data)) { 41 | return $element; 42 | } 43 | return false; 44 | } 45 | 46 | public function delete($id) 47 | { 48 | $element = $this->find($id); 49 | return $element->delete(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Pagebuilder/Exceptions/MissingTranslationsException.php: -------------------------------------------------------------------------------- 1 | model = $language; 14 | } 15 | 16 | public function get() 17 | { 18 | return $this->model->get(); 19 | } 20 | 21 | public function find($id) 22 | { 23 | return $this->model->find($id); 24 | } 25 | 26 | public function create(array $language_data) 27 | { 28 | return $this->model->create($language_data); 29 | } 30 | 31 | public function update($id, array $language_data) 32 | { 33 | $lang = $this->find($id); 34 | if (is_null($lang)) { 35 | throw new Exception('Model not found'); 36 | } 37 | if ($lang->update($language_data)) { 38 | return $lang; 39 | } 40 | return false; 41 | } 42 | 43 | public function destroy($id) 44 | { 45 | $lang = $this->find($id); 46 | return $lang->delete(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Pagebuilder/Livewire/DatePicker.php: -------------------------------------------------------------------------------- 1 | morphMany(Row::class, 'rowable')->orderBy('sorting'); 26 | } 27 | 28 | public function translations() 29 | { 30 | return $this->morphMany(Translation::class, 'translatable'); 31 | } 32 | 33 | //Overrides for polymorphic delete 34 | public function forceDelete() 35 | { 36 | $deleted = parent::forceDelete(); 37 | if ($deleted) { 38 | $this->translations()->delete(); 39 | $this->rows()->delete(); 40 | } 41 | } 42 | 43 | public function getSlugField() 44 | { 45 | return $this->slug_field ?? null; 46 | } 47 | 48 | public function getSlugName() 49 | { 50 | return $this->slug_name; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Pagebuilder/Models/Column.php: -------------------------------------------------------------------------------- 1 | belongsTo(Row::class); 28 | } 29 | 30 | public function element_type() 31 | { 32 | return $this->belongsTo(ElementType::class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Pagebuilder/Models/ColumnTranslation.php: -------------------------------------------------------------------------------- 1 | 'array' 18 | ]; 19 | 20 | 21 | public function column() 22 | { 23 | return $this->belongsTo(Column::class); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Pagebuilder/Models/ElementType.php: -------------------------------------------------------------------------------- 1 | hasMany(Column::class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Pagebuilder/Models/Language.php: -------------------------------------------------------------------------------- 1 | hasMany(Column::class)->orderBy('sorting'); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/Pagebuilder/Models/Translation.php: -------------------------------------------------------------------------------- 1 | 'array' 17 | ]; 18 | 19 | public function language(){ 20 | return $this->belongsTo(Language::class); 21 | } 22 | 23 | public function translatable(){ 24 | return $this->morphTo(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/Pagebuilder/Pagebuilder.php: -------------------------------------------------------------------------------- 1 | rows = $rows; 24 | $this->columns = $columns; 25 | } 26 | 27 | public function get() 28 | { 29 | return $this->model->with([ 30 | 'rows' => function ($q) { 31 | $q->orderBy('sorting')->with(['columns' => function ($q) { 32 | $q->with('translations', 'element_type'); 33 | }]); 34 | }, 35 | 'translations' 36 | ])->get(); 37 | } 38 | 39 | public function find($id) 40 | { 41 | return $this->model->with([ 42 | 'rows' => function ($q) { 43 | $q->orderBy('sorting')->with(['columns' => function ($q) { 44 | $q->with('translations', 'element_type'); 45 | }]); 46 | }, 47 | 'translations' 48 | ])->find($id); 49 | } 50 | 51 | public function setClass($key) 52 | { 53 | $class = config('pagebuilder.builder_classes.' . $key); 54 | $this->model = new $class; 55 | } 56 | 57 | public function create(Request $request) 58 | { 59 | //Grab project data 60 | $data = $request->except('rows', 'translations'); 61 | //Create project entry with basic translations 62 | $article = $this->model->create($data); 63 | //Process translations 64 | $translation_data = $this->processTranslations($request->get('translations')); 65 | //Encode content 66 | $trans_models = $this->encodeContent($translation_data); 67 | //Save results 68 | $article->translations()->saveMany($trans_models); 69 | //Create rows and columns 70 | foreach ($request->get('rows') as $row_key => $row) { 71 | //Create row entry 72 | $current_row = $article->rows()->create($row); 73 | //Create columns 74 | foreach ($row['columns'] as $column_key => $column) { 75 | //Check if column is set 76 | if ($column = $this->processColumn($column)) { 77 | $current_column = $current_row->columns()->create($column); 78 | //Handle actual content 79 | foreach ($column['translations'] as $trans_key => $trans) { 80 | if ($content = $this->processContent($trans_key, $trans)) { 81 | $current_column->translations()->create($content); 82 | } 83 | } 84 | } 85 | } 86 | } 87 | return $article; 88 | } 89 | 90 | public function update($id, Request $request) 91 | { 92 | //Grab basic project 93 | $article = $this->model->with('rows.columns.translations')->find($id); 94 | //Grab request data 95 | $article_data = $request->except('rows', 'translations'); 96 | //Update basic translations 97 | $this->updateTranslations( 98 | $request->get('translations'), 99 | $article 100 | ); 101 | //Update basic project 102 | $article->update($article_data); 103 | //Update rows and columns 104 | foreach ($request->get('rows') as $row_key => $row) { 105 | //Update existing row 106 | if (isset($row['id']) && $current_row = $article->rows->find($row['id'])) { 107 | 108 | $current_row->update($row); 109 | //Run through columns 110 | //dd($row['columns']) 111 | foreach ($row['columns'] as $column) { 112 | if (isset($column['id']) && $current_column = $current_row->columns->where('id', $column['id'])->first()) { 113 | //Update basic column data 114 | $current_column->update($column); 115 | 116 | //Update column translations 117 | foreach ($column['translations'] as $trans_key => $trans) { 118 | //Translation exists: Update 119 | if (isset($trans['id']) && $current_trans = $current_column->translations->find($trans['id'])) { 120 | if ($content = $this->processContent($trans_key, $trans)) { 121 | $current_trans->update($content); 122 | } 123 | } 124 | //No translation yet: Create 125 | else { 126 | //Pass empty translations 127 | if ($content = $this->processContent($trans_key, $trans)) { 128 | $current_column->translations()->create($content); 129 | } 130 | } 131 | } 132 | } else { 133 | if ($column = $this->processColumn($column)) { 134 | $current_column = $current_row->columns()->create($column); 135 | foreach ($column['translations'] as $trans_key => $trans) { 136 | if ($content = $this->processContent($trans_key, $trans)) { 137 | $current_column->translations()->create($content); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | //Create new row 145 | else { 146 | $current_row = $article->rows()->create($row); 147 | //Look for columns 148 | foreach ($row['columns'] as $column) { 149 | if ($column = $this->processColumn($column)) { 150 | $current_column = $current_row->columns()->create($column); 151 | foreach ($column['translations'] as $trans_key => $trans) { 152 | if ($content = $this->processContent($trans_key, $trans)) { 153 | $current_column->translations()->create($content); 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | return $article; 161 | } 162 | 163 | public function delete($id) 164 | { 165 | return $this->model->find($id)->delete(); 166 | } 167 | 168 | //Utilities 169 | private function processContent($trans_key, $trans) 170 | { 171 | if (!is_null($trans) && !empty($this->processTranslations($trans))) { 172 | return $trans; 173 | } 174 | return null; 175 | } 176 | 177 | private function processColumn($column) 178 | { 179 | if ((Arr::get($column, 'element_type_id')) != 0) { 180 | return $column; 181 | } 182 | return null; 183 | } 184 | 185 | //OVERRIDES 186 | 187 | /** 188 | * Filter empty request data from translations 189 | * @param array $arr 190 | * @param type $except 191 | * @return type 192 | */ 193 | public function filterNull(array $arr, $except = null) 194 | { 195 | if (is_null($except)) { 196 | return array_filter($arr, function ($var) { 197 | return !is_null($var) && !empty($var); 198 | }); 199 | } 200 | if (!is_null($except)) { 201 | $filtered = $this->filterNull($arr); 202 | if (isset($filtered[$except]) && count($filtered) == 1) { 203 | return []; 204 | } 205 | return $filtered; 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/Pagebuilder/PagebuilderServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 14 | __DIR__ . '/../config/pagebuilder.php' => config_path('pagebuilder.php'), 15 | ], 'config'); 16 | //load routes 17 | $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); 18 | //migrations 19 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); 20 | //views 21 | $this->loadViewsFrom(__DIR__ . '/../resources/views', 'pagebuilder'); 22 | //language 23 | $this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'pagebuilder'); 24 | } 25 | 26 | /** 27 | * Register the service provider. 28 | */ 29 | public function register() 30 | { 31 | //register commands 32 | $this->commands([ 33 | Commands\ControllerCommand::class, 34 | Commands\ViewCommand::class, 35 | Commands\ModelCommand::class, 36 | Commands\InstallCommand::class, 37 | ]); 38 | //Merge config 39 | $this->mergeConfigFrom( 40 | __DIR__ . '/../config/pagebuilder.php', 41 | 'pagebuilder' 42 | ); 43 | //Run fixed bindings 44 | $this->app->bind(Contracts\ElementContract::class, Elements::class); 45 | $this->app->bind(Contracts\PagebuilderContract::class, Pagebuilder::class); 46 | $this->app->bind(Contracts\RowColumnContract::class, RowColumn::class); 47 | $this->app->bind(Contracts\LanguageContract::class, Languages::class); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Pagebuilder/RowColumn.php: -------------------------------------------------------------------------------- 1 | rows = $rows; 17 | $this->columns = $columns; 18 | } 19 | 20 | public function deleteRow($row_id) 21 | { 22 | $row = $this->rows->find($row_id); 23 | return $row->delete(); 24 | } 25 | 26 | public function deleteColumn($column_id) 27 | { 28 | $column = $this->columns->find($column_id); 29 | return $column->delete(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Pagebuilder/Translations/Translatable.php: -------------------------------------------------------------------------------- 1 | required_trans) && !empty($this->filterNull($trans, $language_key))) { 40 | $approved[] = $this->checkForSlug($trans); 41 | } 42 | } 43 | return $approved; 44 | } 45 | 46 | /** 47 | * Save translations to model 48 | * @param \Illuminate\Database\Eloquent\Model $model 49 | * @param array $translations 50 | * @param string $relation_name 51 | * @return Model 52 | */ 53 | public function saveTranslations( 54 | \Illuminate\Database\Eloquent\Model $model, 55 | array $translations 56 | ) { 57 | 58 | if (empty($translations)) 59 | throw new MissingTranslationsException; 60 | 61 | return $model->{$this->translation_name}()->saveMany($translations); 62 | } 63 | 64 | /** 65 | * 66 | * @param array $arr 67 | * @param type $except 68 | * @return type 69 | */ 70 | public function filterNull(array $arr, $except = null) 71 | { 72 | if (is_null($except)) { 73 | return array_filter($arr, function ($var) { 74 | return !is_null($var); 75 | }); 76 | } 77 | if (!is_null($except)) { 78 | $filtered = $this->filterNull($arr); 79 | if (isset($filtered[$except]) && count($filtered) == 1) { 80 | return []; 81 | } 82 | return $filtered; 83 | } 84 | } 85 | 86 | /** 87 | * 88 | * @param type $translations 89 | * @param \Illuminate\Database\Eloquent\Model $model 90 | * @param string $translation_id 91 | * @param type $translation_class 92 | * @return \Illuminate\Database\Eloquent\Model 93 | */ 94 | public function updateTranslations( 95 | array $translations, 96 | \Illuminate\Database\Eloquent\Model $model 97 | ) { 98 | //Update existing translations 99 | $remaining = []; 100 | foreach ($translations as $trans) { 101 | if (isset($trans['id']) && !is_null($trans['id'])) { 102 | $translation = $model->translations()->where('id', $trans['id'])->first(); 103 | //Update translation and URL slug 104 | $translation->update($this->checkForSlug($trans)); 105 | } else { 106 | $remaining[] = $trans; 107 | } 108 | } 109 | //Create new translations 110 | $new_translations = $this->processTranslations($remaining, true); 111 | //dd($new_translations); 112 | //die(); 113 | if (!empty($new_translations)) { 114 | $trans_models = $this->encodeContent($new_translations); 115 | $model->translations()->saveMany($trans_models); 116 | } 117 | return $model; 118 | } 119 | 120 | public function encodeContent($translation_data) 121 | { 122 | $trans_models = []; 123 | foreach ($translation_data as $trans_item) { 124 | $trans_models[] = new \Flobbos\Pagebuilder\Models\Translation($trans_item); 125 | } 126 | return $trans_models; 127 | } 128 | 129 | /** 130 | * Generate slug from given string 131 | * @param string $name 132 | * @return string 133 | */ 134 | private function generateSlug(string $name): string 135 | { 136 | $slugify = new Slugify(); 137 | return $slugify->slugify($name); 138 | } 139 | 140 | /** 141 | * Check if slug field is set and generate a slug from it 142 | * @param array $trans 143 | * @return array 144 | */ 145 | private function checkForSlug(array $trans): array 146 | { 147 | //Don't use slugs 148 | if (!$this->model->getSlugField()) { 149 | return $trans; 150 | } 151 | //Check if current translation contains a sluggable field 152 | if (array_key_exists($this->model->getSlugField(), Arr::get($trans, 'content', []))) { 153 | $trans[$this->model->getSlugName()] = $this->generateSlug(Arr::get($trans, 'content.' . $this->model->getSlugField())); 154 | } 155 | return $trans; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Pagebuilder/Uploads/Uploadable.php: -------------------------------------------------------------------------------- 1 | file($fieldname)) || !$request->file($fieldname)->isValid()) { 26 | throw new \Exception(trans('crud.invalid_file_upload')); 27 | } 28 | //Get filename 29 | $basename = basename($request->file($fieldname)->getClientOriginalName(), '.' . $request->file($fieldname)->getClientOriginalExtension()); 30 | if ($randomize) { 31 | $filename = Str::slug($basename) . '-' . uniqid() . '.' . $request->file($fieldname)->getClientOriginalExtension(); 32 | } else { 33 | $filename = Str::slug($basename) . '.' . $request->file($fieldname)->getClientOriginalExtension(); 34 | } 35 | //Move file to location 36 | $request->file($fieldname)->storeAs($folder, $filename, $storage_disk); 37 | return $filename; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/config/pagebuilder.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'page' => App\Page::class, 6 | ] 7 | ]; -------------------------------------------------------------------------------- /src/database/migrations/2018_05_11_125042_create_languages_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 19 | $table->string('name'); 20 | $table->string('locale'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('languages'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/database/migrations/2018_05_11_133201_create_element_types_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->string('name'); 19 | $table->string('component'); 20 | $table->string('icon'); 21 | $table->tinyInteger('sorting')->default(0); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('element_types'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_20_065609_create_pages_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->string('name'); 19 | $table->string('photo')->nullable(); 20 | $table->timestamp('published_on')->nullable(); 21 | $table->softDeletes(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('pages'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_20_065917_create_rows_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->morphs('rowable'); 19 | $table->string('custom_class')->nullable(); 20 | $table->integer('sorting')->unsigned()->index(); 21 | $table->boolean('expanded')->default(false); 22 | $table->string('alignment')->nullable(); 23 | $table->string('padding_top')->nullable(); 24 | $table->string('padding_bottom')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('rows'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_20_070220_create_columns_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->foreignId('row_id')->onDelete('cascade'); 19 | $table->foreignId('element_type_id')->onDelete('cascade'); 20 | $table->string('column_size')->nullable(); 21 | $table->string('custom_class')->nullable(); 22 | $table->tinyInteger('sorting')->default(0); 23 | $table->boolean('active')->default(true); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('columns'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_20_082538_create_column_translations_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->foreignId('language_id')->onDelete('cascade'); 19 | $table->foreignId('column_id')->onDelete('cascade'); 20 | $table->json('content'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('column_translations'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_20_084930_create_translations_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->morphs('translatable'); 19 | $table->foreignId('language_id')->onDelete('cascade'); 20 | $table->json('content'); 21 | $table->string('slug')->nullable(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('translations'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/database/migrations/2018_09_26_132707_create_media_table.php: -------------------------------------------------------------------------------- 1 | id('id'); 18 | $table->morphs('model'); 19 | $table->string('collection_name')->nullable(); 20 | $table->string('filetype')->nullable(); 21 | $table->string('filename')->nullable(); 22 | $table->string('disk')->default('public'); 23 | $table->unsignedInteger('size'); 24 | $table->unsignedInteger('order_column')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('media'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/img/pagebuilder/icons/grid-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flobbos/laravel-pagebuilder/a5bf99ec9c6e36cf1bd28a3a25de8c69c7a0db82/src/img/pagebuilder/icons/grid-12.png -------------------------------------------------------------------------------- /src/img/pagebuilder/icons/grid12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flobbos/laravel-pagebuilder/a5bf99ec9c6e36cf1bd28a3a25de8c69c7a0db82/src/img/pagebuilder/icons/grid12.png -------------------------------------------------------------------------------- /src/img/pagebuilder/icons/grid6-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flobbos/laravel-pagebuilder/a5bf99ec9c6e36cf1bd28a3a25de8c69c7a0db82/src/img/pagebuilder/icons/grid6-6.png -------------------------------------------------------------------------------- /src/resources/lang/ar/crud.php: -------------------------------------------------------------------------------- 1 | 'محتوى جديد', 9 | 'save' => 'حفظ', 10 | 'cancel' => 'إلغاء', 11 | 'delete' => 'حذف', 12 | 'edit' => 'تعديل', 13 | //Headlines 14 | 'th_action' => 'العلمية', 15 | 'create_headline' => 'إضافة محتوى جديد', 16 | 'edit_headline' => 'تعديل محتوى ', 17 | //List 18 | 'no_entries' => 'لا يوجد محتويات', 19 | //Messages 20 | 'record_created' => 'تم إضافة المحتوى بنجاح', 21 | 'record_updated' => 'تم تعديل المحتوى بنجاح', 22 | 'record_deleted' => 'تم حذف المحتوى بنجاح', 23 | //File error 24 | 'invalid_file_upload' => 'حدثت مشكلة أثناء تحميل الملف', 25 | 26 | 27 | // TODO 28 | 'element_types' => 'Elements', 29 | 'languages' => 'Languages', 30 | 31 | // Labels 32 | 'labels' => [ 33 | 'name' => 'Name', 34 | 'iso' => 'ISO', 35 | 'sorting' => 'Sorting', 36 | 'icon' => 'Icon', 37 | 'component' => 'Component' 38 | ] 39 | ]; 40 | -------------------------------------------------------------------------------- /src/resources/lang/de/crud.php: -------------------------------------------------------------------------------- 1 | 'Neuer Eintrag', 9 | 'save' => 'Speichern', 10 | 'cancel' => 'Abbrechen', 11 | 'delete' => 'Löschen', 12 | 'edit' => 'Editieren', 13 | //Headlines 14 | 'th_action' => 'Aktion', 15 | 'create_headline' => 'Neuen Eintrag erstellen', 16 | 'edit_headline' => 'Eintrag editieren', 17 | //List 18 | 'no_entries' => 'Keine Einträge gefunden.', 19 | //Messages 20 | 'record_created' => 'Ein neuer Eintrag wurde erfolgreich erstellt.', 21 | 'record_updated' => 'Der Eintrag wurde erfolgreich aktualisiert.', 22 | 'record_deleted' => 'Der Eintrag wurde erfolgreich gelöscht.', 23 | 'record_restored' => 'Der Eintrag wurde erfolgreich wiederhergestellt.', 24 | //File error 25 | 'invalid_file_upload' => 'Es gab ein Problem beim Upload der Datei.', 26 | 27 | 'element_types' => 'Elemente', 28 | 'languages' => 'Sprachen', 29 | 30 | // Labels 31 | 'labels' => [ 32 | 'name' => 'Name', 33 | 'iso' => 'ISO', 34 | 'sorting' => 'Sortierung', 35 | 'icon' => 'Icon', 36 | 'component' => 'Komponente' 37 | ] 38 | ]; 39 | -------------------------------------------------------------------------------- /src/resources/lang/en/crud.php: -------------------------------------------------------------------------------- 1 | 'New entry', 9 | 'save' => 'Save', 10 | 'cancel' => 'Cancel', 11 | 'delete' => 'Delete', 12 | 'edit' => 'Edit', 13 | //Headlines 14 | 'th_action' => 'Action', 15 | 'create_headline' => 'Create new entry', 16 | 'edit_headline' => 'Edit entry', 17 | //List 18 | 'no_entries' => 'No entries found.', 19 | //Messages 20 | 'record_created' => 'A new entry has been successfully created.', 21 | 'record_updated' => 'The entry has been successfully updated.', 22 | 'record_deleted' => 'The entry was removed successfully', 23 | 'record_restored' => 'The entry has been restored successfully', 24 | //File error 25 | 'invalid_file_upload' => 'A problem was encountered during the file upload', 26 | 27 | 'element_types' => 'Elements', 28 | 'languages' => 'Languages', 29 | 30 | // Labels 31 | 'labels' => [ 32 | 'name' => 'Name', 33 | 'iso' => 'ISO', 34 | 'sorting' => 'Sorting', 35 | 'icon' => 'Icon', 36 | 'component' => 'Component' 37 | ] 38 | ]; 39 | -------------------------------------------------------------------------------- /src/resources/stubs/controllers/page_controller.stub: -------------------------------------------------------------------------------- 1 | builder = $builder; 18 | //Init pagebuilder model class 19 | $this->builder->setClass('DummySetClass'); 20 | } 21 | 22 | /** 23 | * Display a listing of the resource. 24 | * 25 | * @return \Illuminate\Http\Response 26 | */ 27 | public function index(){ 28 | return view('DummyViewPath.index')->with(['DummyVariables'=>$this->builder->get()]); 29 | } 30 | 31 | /** 32 | * Show the form for creating a new resource. 33 | * 34 | * @return \Illuminate\Http\Response 35 | */ 36 | public function create(LanguageContract $lang, ElementContract $element_types){ 37 | return view('DummyViewPath.create')->with([ 38 | 'languages' => $lang->get(), 39 | 'element_types' => $element_types->get() 40 | ]); 41 | } 42 | 43 | /** 44 | * Store a newly created resource in storage. 45 | * 46 | * @param \Illuminate\Http\Request $request 47 | * @return \Illuminate\Http\Response 48 | */ 49 | public function store(Request $request){ 50 | try{ 51 | $DummyVariable = $this->builder->create($request); 52 | return response()->json([ 53 | 'success'=>true, 54 | 'return_url' => route('DummyRoute.edit',$DummyVariable->id) 55 | ],200); 56 | } catch (Exception $ex) { 57 | return response()->json(['success'=>false,'message'=>$ex->getMessage().'--'.$ex->getLine().'--'.$ex->getFile()],422); 58 | } 59 | } 60 | 61 | 62 | /** 63 | * Show the form for editing the specified resource. 64 | * 65 | * @param int $id 66 | * @return \Illuminate\Http\Response 67 | */ 68 | public function edit($id, LanguageContract $lang, ElementContract $element_types){ 69 | return view('DummyViewPath.edit')->with([ 70 | 'DummyVariable'=>$this->builder->find($id), 71 | 'languages'=>$lang->get(), 72 | 'element_types' => $element_types->get() 73 | ]); 74 | } 75 | 76 | /** 77 | * Update the specified resource in storage. 78 | * 79 | * @param \Illuminate\Http\Request $request 80 | * @param int $id 81 | * @return \Illuminate\Http\Response 82 | */ 83 | public function update(Request $request, $id){ 84 | try{ 85 | $this->builder->update($id, $request); 86 | return response()->json([ 87 | 'success'=>true, 88 | 'return_url'=>route('DummyRoute.edit',$id) 89 | ],200); 90 | } catch (Exception $ex) { 91 | return response()->json(['success'=>false,'message'=>$ex->getMessage().' --- '.$ex->getLine().' ---- '.$ex->getFile()],422); 92 | } 93 | } 94 | 95 | /** 96 | * Remove the specified resource from storage. 97 | * 98 | * @param int $id 99 | * @return \Illuminate\Http\Response 100 | */ 101 | public function destroy($id){ 102 | try{ 103 | $this->builder->delete($id); 104 | return redirect()->route('DummyRoute.index')->withMessage(trans('pagebuilder::crud.record_deleted')); 105 | } catch (Exception $ex) { 106 | return redirect()->route('DummyRoute.index')->withErrors($ex->getMessage()); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/resources/stubs/models/page.stub: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Create Page') }} 5 |

6 |
7 |
8 |
9 |
10 |

@lang('pagebuilder::crud.create_headline')

11 |
12 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /src/resources/stubs/views/pages/edit.stub: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Edit Page') }} 5 |

6 |
7 |
8 |
9 |
10 |

@lang('pagebuilder::crud.create_headline')

11 |
12 |
13 |
14 |
-------------------------------------------------------------------------------- /src/resources/stubs/views/pages/index.stub: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Pages') }} 5 |

6 |
7 |
8 |
9 |
10 |
11 |
12 |

13 |
14 | 19 |
20 |
21 |
22 | @include('pagebuilder::notifications') 23 | @if($articles->isEmpty()) 24 | @lang('pagebuilder::crud.no_entries') 25 | @else 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | @foreach($articles as $article) 36 | 37 | 38 | 39 | 54 | 55 | @endforeach 56 | 57 |
#Name
{{$article->id}}{{$article->name}} 40 |
41 | 42 | @lang('pagebuilder::crud.edit') 43 | 44 |
47 | {{ csrf_field() }} 48 | {{ method_field('DELETE') }} 49 | 51 |
52 |
53 |
58 | @endif 59 |
60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /src/resources/views/element-types/create.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Create Element') }} 5 |

6 |
7 |
8 |
9 | {{ csrf_field() }} 10 |
11 |
12 |

Elemente

13 | @lang('pagebuilder::crud.create_headline') 14 |
15 |
16 | @include('pagebuilder::notifications') 17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 | 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /src/resources/views/element-types/edit.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Edit Element') }} 5 |

6 |
7 |
8 |
9 | {{ csrf_field() }} 10 |
11 |
12 |

Elemente

13 | @lang('pagebuilder::crud.create_headline') 14 |
15 |
16 | @include('pagebuilder::notifications') 17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 | 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
-------------------------------------------------------------------------------- /src/resources/views/element-types/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Edit Element') }} 5 |

6 |
7 |
8 |
9 |
10 |
11 |
12 |

Elemente

13 |
14 | 19 |
20 |
21 |
22 | @include('pagebuilder::notifications') 23 | @if($element_types->isEmpty()) 24 | @lang('pagebuilder::crud.no_entries') 25 | @else 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | @foreach($element_types as $element_type) 36 | 37 | 38 | 39 | 54 | 55 | @endforeach 56 | 57 |
#Name
{{$element_type->sorting}}{{$element_type->name}} 40 |
41 | 42 | @lang('pagebuilder::crud.edit') 43 | 44 |
47 | {{ csrf_field() }} 48 | {{ method_field('DELETE') }} 49 | 51 |
52 |
53 |
58 | @endif 59 |
60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /src/resources/views/languages/create.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Create Language') }} 5 |

6 |
7 |
8 |
9 | {{ csrf_field() }} 10 |
11 |
12 |

Languages

13 |
14 |
15 | @include('pagebuilder::notifications') 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 | 34 | 35 |
36 | 37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /src/resources/views/languages/edit.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Edit Language') }} 5 |

6 |
7 |
8 |
9 | {{ csrf_field() }} 10 | {{method_field('PUT')}} 11 |
12 |
13 |

Languages

14 |
15 |
16 | @include('pagebuilder::notifications') 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 | 30 |
31 | 32 | 35 | 36 |
37 | 38 |
39 | 40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /src/resources/views/languages/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Languages') }} 5 |

6 |
7 |
8 |
9 |
10 |
11 |
12 |

Sprachen

13 |
14 | 19 |
20 | 21 |
22 | @include('pagebuilder::notifications') 23 | @if($languages->isEmpty()) 24 | @lang('pagebuilder::crud.no_entries') 25 | @else 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | @foreach($languages as $lang) 37 | 38 | 39 | 40 | 41 | 46 | 47 | @endforeach 48 | 49 |
#NameISO
{{ $lang->id }}{{ $lang->name }}{{ $lang->locale }} 42 | 43 | @lang('pagebuilder::crud.edit') 44 | 45 |
50 | @endif 51 |
52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /src/resources/views/livewire/date-picker.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 11 | 12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 | 20 | 28 | 29 |
30 | 31 | 32 | 33 |
34 | 35 | 36 | 39 | 40 |
45 | 46 |
47 |
48 | 49 | 50 |
51 |
52 | 62 | 72 |
73 |
74 | 75 |
76 | 83 |
84 | 85 |
86 | 92 | 102 |
103 |
104 | 105 |
106 |
107 | 108 |
109 |
110 | 111 | 172 |
173 |
-------------------------------------------------------------------------------- /src/resources/views/livewire/settings.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | Hello! 4 |
-------------------------------------------------------------------------------- /src/resources/views/main.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Pagebuilder Dashboard') }} 5 |

6 |
7 |
8 |
9 |
10 |

Pagebuilder

11 |
12 |
13 |
14 | Elements: {{ $elements->count() }} 15 |
16 |
17 | Languages: {{ $languages->count() }} 18 |
19 |
20 |
21 |
22 |
-------------------------------------------------------------------------------- /src/resources/views/notifications.blade.php: -------------------------------------------------------------------------------- 1 | @if (count($errors) > 0) 2 |
4 |
5 | 10 |
11 |
12 | 15 |
16 |
17 | @endif 18 | 19 | @if(session()->has('message')) 20 |
22 |
23 | {{ session('message') }} 24 |
25 |
26 | 29 |
30 |
31 | @endif 32 | -------------------------------------------------------------------------------- /src/routes/web.php: -------------------------------------------------------------------------------- 1 | ['web', 'auth'], 'prefix' => 'pagebuilder', 'as' => 'pagebuilder::'], function () { 9 | Route::get('/', [PagebuilderController::class, 'index'])->name('home'); 10 | //Resource route for languages 11 | Route::resource('languages', LanguageController::class); 12 | //Resource route for elements 13 | Route::resource('element-types', ElementTypeController::class); 14 | //Upload photos 15 | Route::post('upload-photo', [UploadController::class, 'store'])->name('upload'); 16 | //Delete Photos 17 | Route::delete('delete-photo', [UploadController::class, 'destroy'])->name('delete-photo'); 18 | //Delete entire row 19 | Route::delete('delete-row', [PagebuilderController::class, 'deleteRow'])->name('delete-row'); 20 | //Delete Column 21 | Route::delete('delete-column', [PagebuilderController::class, 'deleteColumn'])->name('delete-column'); 22 | }); 23 | --------------------------------------------------------------------------------