Installation
composer require altuma/articlebundle
Add to config/app.php under providers:
Altuma\ArticleBundle\ArticleBundleServiceProvider::class,
Publish the bundle's migrations and config:
php artisan vendor:publish --provider="Altuma\ArticleBundle\ArticleBundleServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="Altuma\ArticleBundle\ArticleBundleServiceProvider" --tag="config"
Run migrations:
php artisan migrate
First Use Case: Creating an Article
Use the Article model (auto-registered via the service provider):
use Altuma\ArticleBundle\Models\Article;
$article = Article::create([
'title' => 'My First Article',
'slug' => 'my-first-article',
'content' => '<p>Hello, world!</p>',
'status' => 'published', // or 'draft', 'archived'
]);
Key Config
Check config/article.php for default settings like:
default_statusallowed_statusescontent_editor (e.g., ckeditor, tinymce)CRUD Operations
Use Eloquent methods directly on the Article model:
// Fetch published articles
$articles = Article::where('status', 'published')->latest()->get();
// Update article
$article->update(['content' => '<p>Updated content</p>']);
Slug Generation
Auto-generate slugs via the sluggable trait (if enabled in config):
$article = Article::create([
'title' => 'New Article',
// Slug auto-generated from title
]);
Status Transitions
Use the changeStatus() method to handle workflows:
$article->changeStatus('draft'); // Validates against allowed_statuses
Content Management
Integrate with editors via the content field (e.g., CKEditor):
// In a form request
$validated = $request->validate([
'content' => 'required|string',
]);
API Integration Use Laravel's API resources:
php artisan make:resource ArticleResource
Then:
return new ArticleResource(Article::paginate(10));
Custom Fields
Extend the Article model or use morph maps for custom field types:
// Example: Add a 'featured_image' field
$article->update(['featured_image' => 'path/to/image.jpg']);
Event Listeners
Listen to article events (e.g., ArticlePublished):
// In EventServiceProvider
protected $listen = [
'Altuma\ArticleBundle\Events\ArticlePublished' => [
'App\Listeners\SendArticleNotification',
],
];
Policy Integration Define policies for authorization:
php artisan make:policy ArticlePolicy --model=Article
Then restrict access:
$this->authorize('update', $article);
Tagging/Categorization Use many-to-many relationships (if the bundle supports it):
$article->categories()->attach([1, 2, 3]);
SEO Optimization
Leverage the meta_title and meta_description fields:
$article->update([
'meta_title' => 'SEO Title',
'meta_description' => 'SEO Description',
]);
Slug Conflicts
slug is unique. Use Str::slug() manually if auto-generation fails:
$slug = Str::slug($title).'-'.time();
Status Validation
changeStatus() method enforces allowed_statuses in config. Override the trait if custom logic is needed:
public function changeStatus($status) {
if (!in_array($status, $this->getAllowedStatuses())) {
throw new \InvalidArgumentException("Invalid status: {$status}");
}
$this->status = $status;
$this->save();
}
Content Editor Integration
content field is saved as HTML. Sanitize input to prevent XSS:
use Purifier;
$cleanContent = Purifier::clean($request->content);
Migration Conflicts
articles table, run:
php artisan migrate:fresh --env=testing
in a test environment to avoid conflicts.Caching Headaches
php artisan route:clear
Bulk Actions Use query builder for bulk updates:
Article::where('status', 'draft')->update(['status' => 'published']);
Soft Deletes Enable soft deletes in the model:
use SoftDeletes;
class Article extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
}
Localization
Store translations in a translations JSON column:
$article->update([
'translations' => json_encode([
'en' => ['title' => 'English Title'],
'fr' => ['title' => 'Titre Français'],
]),
]);
Testing Use factories for testing:
php artisan make:factory ArticleFactory --model=Article
Example factory:
$factory->define(Article::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'slug' => $faker->slug,
'content' => $faker->paragraph,
'status' => 'published',
];
});
Performance
Schema::table('articles', function (Blueprint $table) {
$table->index('slug');
$table->index('status');
});
with() for eager loading:
$articles = Article::with('categories')->get();
Custom Validation
Extend the Article model for custom rules:
public static function boot() {
parent::boot();
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('status', '!=', 'archived');
});
}
Asset Management Store article assets (images, PDFs) in a dedicated directory:
$path = storage_path('app/articles/'.$article->id.'/image.jpg');
How can I help you explore Laravel packages today?