Installation Add the package via Composer:
composer require bitcreator/content-bundle
Publish the configuration (if needed):
php artisan vendor:publish --provider="BitCreator\ContentBundle\ContentBundleServiceProvider"
First Use Case: Basic Content Model Define a content model in a migration:
Schema::create('content_items', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body')->nullable();
$table->string('slug')->unique();
$table->timestamps();
});
Create a model extending BitCreator\ContentBundle\Models\ContentModel:
namespace App\Models;
use BitCreator\ContentBundle\Models\ContentModel;
class ContentItem extends ContentModel
{
protected $table = 'content_items';
}
Basic CRUD Operations
// Create
$item = new \App\Models\ContentItem();
$item->title = 'Hello World';
$item->body = 'This is a test.';
$item->save();
// Retrieve
$item = \App\Models\ContentItem::find(1);
// Update
$item->title = 'Updated Title';
$item->save();
// Delete
$item->delete();
Leveraging Bundle Features
Check the config/content-bundle.php for default settings (e.g., caching, slug generation rules).
Slug Generation Use the built-in sluggable trait for automatic slug creation:
use BitCreator\ContentBundle\Traits\Sluggable;
class ContentItem extends ContentModel
{
use Sluggable;
protected $slugField = 'slug';
protected $slugSource = 'title';
}
Versioning Enable versioning in the model:
class ContentItem extends ContentModel
{
protected $versioned = true;
}
Access versions via:
$versions = $item->versions()->get();
Localization If the bundle supports localization, define translatable fields:
class ContentItem extends ContentModel
{
protected $translatable = ['title', 'body'];
}
API Resources Create a resource for API responses:
namespace App\Http\Resources;
use App\Models\ContentItem;
use Illuminate\Http\Resources\Json\JsonResource;
class ContentItemResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'body' => $this->body,
'created_at' => $this->created_at,
];
}
}
Form Requests Validate content submissions:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContentItemRequest extends FormRequest
{
public function rules()
{
return [
'title' => 'required|string|max:255',
'body' => 'nullable|string',
];
}
}
Events & Observers
Listen to content events (e.g., ContentCreated, ContentUpdated):
namespace App\Listeners;
use BitCreator\ContentBundle\Events\ContentCreated;
class LogContentCreation
{
public function handle(ContentCreated $event)
{
\Log::info('New content created: ' . $event->content->title);
}
}
Extend ContentModel Override methods for custom logic:
class ContentItem extends ContentModel
{
public function getFullTitleAttribute()
{
return "Published: " . $this->title;
}
}
Query Scopes Add reusable query logic:
class ContentItem extends ContentModel
{
public function scopePublished($query)
{
return $query->where('published_at', '<=', now());
}
}
Middleware for Content Access Protect routes with middleware:
Route::get('/content/{item}', function (ContentItem $item) {
return $item;
})->middleware('can:view,content');
Slug Conflicts
slugSource is unique per model.$item->slug = \Str::slug($item->title) . '-' . rand(100, 999);
Versioning Overhead
protected $versioned = false;
Caching Quirks
php artisan cache:clear
config/content-bundle.php.Localization Pitfalls
Enable Query Logging
Add to AppServiceProvider:
\DB::enableQueryLog();
$queries = \DB::getQueryLog();
Check for Silent Failures Wrap bundle operations in try-catch:
try {
$item->save();
} catch (\Exception $e) {
\Log::error('Content save failed: ' . $e->getMessage());
}
Verify Model Bindings Ensure route model binding works:
Route::get('/content/{item}', function (ContentItem $item) {
// $item will be null if binding fails
});
Custom Storage Engines
Override storage logic in ContentModel:
protected function getStoragePath()
{
return storage_path('app/content/' . $this->slug);
}
Add Fields Dynamically Use model events to attach metadata:
class ContentItem extends ContentModel
{
protected static function booted()
{
static::created(function ($item) {
$item->metadata()->create(['key' => 'author', 'value' => auth()->id()]);
});
}
}
Hook into Bundle Events
Listen for core events (e.g., ContentSaving, ContentDeleting):
\Event::listen('BitCreator\ContentBundle\Events\ContentSaving', function ($event) {
$event->content->touch();
});
Override Default Config Publish and extend the config:
'slug' => [
'max_length' => 150, // Override default
],
How can I help you explore Laravel packages today?