This package has been abandoned, use with caution if you still need it.
Please fork this package and give it new life if you're interested!
This package allows you to associate content bricks to Eloquent models and provides a fully customizable admin panel to manage them.
This package is shipped with few pre-built brickables. You can use them as is but you definitely should consider them as examples: customizing them or create new ones has been designed to be simple as hell! :fire:
Found this package helpful? Please consider supporting my work!
Laravel version | PHP version | Package version |
---|---|---|
^9.0 | ^10.0 | 8.1. | 8.2. | ^3.2 |
^8.0 | ^9.0 | ^8.1 | ^8.2 | ^3.1 |
^8.0 | ^9.0 | ^8.0 | ^8.1 | ^3.0 |
^7.0 | ^8.0 | ^7.4 | ^8.0 | ^2.0 |
^5.8 | ^6.0 | ^7.0 | ^7.1 | ^7.2 | ^7.3 | ^7.4 | ^1.0 |
Associate content bricks to Eloquent models:
$page = Page::find(1);
// Associate one content brick
$page->addBrick(OneTextColumn::class, ['text' => 'Text']);
// Or associate several content bricks at once
$page->addBricks([
[OneTextColumn::class, ['text' => 'Text']],
[TwoTextColumns::class, ['text_left' => 'Left text', 'text_right' => 'Right text']]
]);
Display bricks in your views:
{{-- All at once --}}
{!! $page->displayBricks() !!}
{{-- Or one by one --}}
{{ $page->getFirstBrick(OneTextColumn::class) }}
Display the model-related bricks admin panel in your views:
{{ $page->displayAdminPanel() }}
Install the package via composer:
composer require okipa/laravel-brickables
Then, publish and run the database migrations:
php artisan vendor:publish --tag=laravel-brickables:migrations
php artisan migrate
Finally, to benefit from smart loading of brickables css and js resources, add these directives to your blade layout as shown in the example bellow:
{{-- layout.blade.php --}}
<html>
<head>
@brickablesCss
</head>
<body>
@yield('content')
@brickablesJs
</body>
</html>
Publish the package configuration:
php artisan vendor:publish --tag=laravel-brickables:config
:warning: You may have to run a composer dump-autoload
after changing a path in your configuration file.
Publish the package views:
php artisan vendor:publish --tag=laravel-brickables:views
All words and sentences used in this package are translatable.
See how to translate them on the Laravel official documentation : https://laravel.com/docs/localization#using-translation-strings-as-keys.
Here is the list of the words and sentences available for translation by default:
Content Bricks
No saved content brick.
Content
Left content
Right content
Brick data
Add
Edit
Update
Destroy
Cancel
Move up
Move down
The entry :model > :brickable has been created.
The entry :model > :brickable has been updated.
The entry :model > :brickable has been deleted.
You will also have to define the validation.attributes.brickable_types
translation.
Finally, you will have to translate each registered brickable label translation.
Implement the HasBrickables
interface and use the HasBrickablesTrait
trait to any Eloquent model that you want to be able to be associated to content bricks to.
use Illuminate\Database\Eloquent\Model;
use Okipa\LaravelBrickables\Contracts\HasBrickables;
use Okipa\LaravelBrickables\Traits\HasBrickablesTrait;
class Page extends Model implements HasBrickables
{
use HasBrickablesTrait;
// ...
}
Add the web
routes that will be required by the content bricks admin panel:
Brickables::routes();
These routes are consuming the Okipa\LaravelBrickables\Controllers\BricksController
controller by default.
To customize the admin panel actions, you can add routes inside or outside of the brickables route group.
Brickables::routes(function(){
// Inside the routes group: will benefit from the CRUDBrickable middleware.
});
// Outside the route group: will not benefit from the CRUDBrickable middleware.
Check the Empower bricks with extra abilities part to get more information about the customization possibilities.
In your Eloquent model, you optionally can define constraints:
use Illuminate\Database\Eloquent\Model;
use Okipa\LaravelBrickables\Contracts\HasBrickables;
use Okipa\LaravelBrickables\Traits\HasBrickablesTrait;
class Page extends Model implements HasBrickables
{
use HasBrickablesTrait;
public array $brickables = [
'can_only_handle' => [OneTextColumn::class], // By default all registered brickables can be handled.
'number_of_bricks' => [OneTextColumn::class => ['min' => 1, 'max' => 3]], // By default, there are no number restrictions.
];
// ...
}
In this example:
Page
model will only be allowed to handle OneTextColumn
bricks.OneTextColumn
bricks.OneTextColumn
brick if there is only one left.OneTextColumn
bricks if 3 are already added.OneTextColumn
one with the highest position.OneTextColumn
brick will thrown a ModelHasReachedMaxNumberOfBricksException
.Important note: you can disable a brickable management for a model by setting its max number to 0
.
Associate a single content brick to an Eloquent model:
$brick = $page->addBrick(OneTextColumn::class, ['text' => 'Text']);
You also can associate several content bricks at once:
$bricks = $page->addBricks([
[OneTextColumn::class, ['text' => 'Text']],
[TwoTextColumns::class, ['text_left' => 'Left text', 'text_right' => 'Right text']]
]);
Just update your content brick as you would fo for any other Eloquent model instance:
// As data are stored in json, you will have to process this way: https://github.com/laravel/framework/pull/15464#issuecomment-247642772.
$brick->data = ['text' => 'Another text'];
$brick->save();
Just delete your content brick as you would fo for any other Eloquent model instance:
$brick->delete();
Clear all the content bricks associated to an Eloquent model, or only those with specific brickable types:
$page->clearBricks();
$page->clearBricks([OneTextColumn::class]);
Clear all the content bricks except specific ones:
$page->clearBricksExcept($bricksCollection);
Note
By default, all bricks are ordered by their creation order (last created at the end).
The Brick
model uses the spatie/eloquent-sortable
package to handle the content bricks positioning.
To see how to use this third party package, check its documentation here: https://github.com/spatie/eloquent-sortable.
You may note that the bricks order management is already handled in the provided admin panel and that you can use it as is.
Retrieve all the content bricks associated to an Eloquent model, or only those with a specific brickable type:
$bricks = $page->getBricks();
$bricks = $page->getBricks(OneTextColumn::class);
Get the first content brick associated to an Eloquent model, or the one with a specific brickable type:
$brick = $page->getFirstBrick();
$brick = $page->getFirstBrick(OneTextColumn::class);
As each brickable can specify its own brick model, you should query content bricks and then cast them ito the model defined in their related brickable:
$rawBricks = Brick::where('model_type', Page::class)->where('model_id', 1)->where('brickable_type', OneTextColumn::class)->get();
$bricks = Brickables::castBricks($rawBricks);
Display a single content brick in your view:
{{ $page->getFirstBrick(OneTextColumn::class) }}
Or display all the content bricks associated to an Eloquent model:
{!! $page->displayBricks() !!}
Or only display content bricks from given brickable types:
{!! $page->displayBricks([OneTextColumn::class, TwoTextColumns::class]) !!}
Get all the registered brickables:
$registeredBrickables = $page->getRegisteredBrickables();
Get all the brickables that are allowed to be added to an Eloquent model:
$additionableBrickables = $page->getAdditionableBrickables();
Retrieve a brickable from a brick instance:
$brickable = $page->getFirstBrick(OneTextColumn::class)->brickable;
Use the ready-to-use admin panel to manage related-model content bricks:
{!! $page->displayAdminPanel() !!}
Customize the admin panel views by publishing them.
:bulb: Tips
Create a new brickable class that extends class in your app/vendor/Brickables
directory.
In your brickable class, you can override any method from the extended abstract Brickable
to customize the brickable behaviour.
<?php
namespace App\Vendor\LaravelBrickables\Brickables;
use Okipa\LaravelBrickables\Abstracts\Brickable;
class MyNewBrickable extends Brickable
{
public function validateStoreInputs(): array
{
return request()->validate(['text' => ['required', 'string']]);
}
public function validateUpdateInputs(): array
{
return request()->validate(['text' => ['required', 'string']]);
}
// Alternative example: use a form request to validate your inputs and return the validated fields.
//public function validateStoreInputs(): array
//{
// return app(MyNewBrickableStoreFormRequest::class)->validated();
//}
}
Then, register it in your config('brickables.registered')
array:
<?php
return [
'registered' => [
// Other brickables declarations...
App\Vendor\LaravelBrickables\Brickables\MyNewBrickable::class,
],
];
Finally, create the brickable views in the resources/views/vendor/laravel-brickables/my-new-brickable
directory (you can customize the view paths in your MyNewBrickable
class):
brick
view that will be used to display your MyNewBrickable
brick in the front.form
view which will embed the form inputs that will be used to CRUD your MyNewBrickable
bricks in the admin panel.You should see the existing brickables implementation to get familiar with their management.
Your brickable is now ready to be associated to Eloquent models.
You have the possibility to define a css and js resource to customize each brickable rendering.
In addition, this package embeds a smart resource management system : it determines which brickables are actually displayed on the page and only loads the resources once, even if a brickable is used more than once on the page.
To benefit from this feature, make sure you have implemented the @brickablesCss
and the @brickablesJs
directives as precised in the installation part.
Then, define which resources your brickables are using:
<?php
namespace App\Vendor\LaravelBrickables\Brickables;
use Okipa\LaravelBrickables\Abstracts\Brickable;
class MyNewBrickable extends Brickable
{
// ...
protected function setCssResourcePath(): string|null
{
return mix('/css/brickables/my-new-brickable.css');
}
protected function setJsResourcePath(): string|null
{
return mix('/js/brickables/my-new-brickable.js');
}
}
Finally, use the @brickableResourcesCompute
directive under the last displayed brick in the page:
{{-- page.blade.php --}}
@extends('laravel-brickables::layout')
@section('content')
{{ $page->getFirstBrick(OneTextColumn::class) }}
{{ $page->displayBricks([TwoTextColumns::class]) }}
@brickableResourcesCompute
@endsection
:warning: Important: Please note that you will always have to declare the @brickableResourcesCompute
directive from a child view from the one which is declaring the brickablesCss
and @brickablesJs
directives. As you can see in our example, the @brickableResourcesCompute
blade directive is called on the page.blade.php
view, which is a child of layout.blade.php
(where the brickablesCss
and @brickablesJs
are declared). This is the only way for this package to know which brickables are actually displayed on the page, in order to intelligently load the resources.
To add abilities to your brickables, you will have to implement the additional treatments in the brickable-related brick model and brick controller.
Let's add the ability to manage images in our MyNewBrickable
from the previous example.
First create a MyNewBrickableBrick
model that will extend the Okipa\LaravelBrickables\Models\Brick
one in order to give the image management ability to this brick.
<?php
namespace App;
use Okipa\LaravelBrickables\Models\Brick;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class MyNewBrickableBrick extends Brick implements HasMedia
{
// Image management example with the spatie/laravel-medialibrary package.
use InteractsWithMedia;
// Optimize query by eager loading media relations.
protected $with = ['media'];
// ...
}
Then, create a MyNewBrickableBricksController
model which will extend the Okipa\LaravelBrickables\Controllers\BricksController
one where you will add the image management treatments.
<?php
namespace App\Http\Controllers;
use Okipa\LaravelBrickables\Controllers\BricksController;
class MyNewBrickableBricksController extends BricksController
{
// ...
protected function stored(Request $request, Brick $brick): void
{
// Image management example with the spatie/laravel-medialibrary package
$brick->addMediaFromRequest('image')->toMediaCollection('bricks');
}
protected function updated(Request $request, Brick $brick): void
{
// Image management example with the spatie/laravel-medialibrary package
if ($request->file('image')) {
$brick->addMediaFromRequest('image')->toMediaCollection('bricks');
}
}
// ...
}
Do not forget to validate your form inputs:
class MyNewBrickable extends Brickable
{
public function validateStoreInputs(): array
{
return request()->validate([
'text' => ['required', 'string'],
'image' => ['required', 'mimetypes:image/jpeg,image/png', 'dimensions:min_width=240,min_height=160', 'max:5000'],
]);
}
public function validateUpdateInputs(): array
{
return request()->validate([
'text' => ['required', 'string'],
'image' => ['nullable', 'mimetypes:image/jpeg,image/png', 'dimensions:min_width=240,min_height=160', 'max:5000'],
]);
}
}
Finally, tell you brickable to use your MyNewBrickableBrick
model and your MyNewBrickableBricksController
controller:
<?php
namespace App\Vendor\LaravelBrickables\Brickables;
use App\MyNewBrickableBrick;
use App\Http\Controllers\MyNewBrickableBricksController;
use Okipa\LaravelBrickables\Abstracts\Brickable;
class MyNewBrickable extends Brickable
{
// ...
protected function setBrickModelClass(): string
{
return MyNewBrickableBrick::class;
}
protected function setBricksControllerClass(): string
{
return MyNewBrickableBricksController::class;
}
// ...
}
That's it, your custom model and controller will now be used by the MyNewBrickable
brickable.
It can be useful to retrieve the Eloquent model from the request, for navigation concerns, for example.
This helper will be able to return the related model when navigating on the brickables form views (bricks creation and edition requests).
// You can pass a custom request in the parameters. If none is given, the current request is used.
$model = Brickables::getModelFromRequest();
composer test
Please see CHANGELOG for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email arthur.lorent@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.