brt/blog-bundle
Laravel blog bundle providing posts, categories, tags, and basic blog routes/views. Quick setup for adding a simple blog section to an existing app, with migrations and optional admin tooling depending on configuration.
Abandon Direct Use: This bundle is not Laravel-compatible. Instead, use these alternatives:
composer require laravel/nova laravel/breeze --dev
php artisan nova:install
php artisan breeze:install blog
First Use Case (Laravel Alternative): Create a post model and migration:
php artisan make:model Post -m
Define migration (database/migrations/..._create_posts_table.php):
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->string('slug')->unique();
$table->foreignId('user_id')->constrained();
$table->timestamps();
});
Run migration:
php artisan migrate
Create a controller:
php artisan make:controller PostController --resource
Add routes (routes/web.php):
Route::resource('posts', PostController::class);
Where to Look First:
Model-View-Controller (MVC) Pattern:
Post with relationships (e.g., belongsTo(User)).
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
public function user() { return $this->belongsTo(User::class); }
}
// app/Http/Controllers/PostController.php
public function index() {
return view('posts.index', ['posts' => Post::latest()->paginate(10)]);
}
<!-- resources/views/posts/index.blade.php -->
@foreach($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ Str::limit($post->content, 200) }}</p>
</article>
@endforeach
File Uploads (Replacing VichUploader):
composer require spatie/laravel-medialibrary
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider"
Post model:
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Post extends Model implements HasMedia {
use InteractsWithMedia;
}
public function store(Request $request) {
$post = Post::create($request->validate([
'title' => 'required',
'content' => 'required',
'image' => 'nullable|image'
]));
if ($request->hasFile('image')) {
$post->addMediaFromRequest('image')->toMediaCollection('images');
}
return redirect()->route('posts.show', $post);
}
Pagination (Replacing KnpPaginator):
$posts = Post::latest()->paginate(10); // Returns a LengthAwarePaginator
{{ $posts->links() }} <!-- Default pagination links -->
$posts = Post::latest()->paginate(10, ['*'], 'custom');
CLI Commands (Replacing Bundle Commands):
php artisan make:command CreatePost
// app/Console/Commands/CreatePost.php
public function handle() {
$post = Post::create([
'title' => $this->ask('Title'),
'content' => $this->ask('Content'),
'slug' => Str::slug($this->ask('Slug')),
'user_id' => auth()->id()
]);
$this->info("Post created: {$post->slug}");
}
app/Console/Kernel.php:
protected $commands = [
\App\Console\Commands\CreatePost::class,
];
php artisan create:post
User Integration:
User model or extend it:
// app/Models/User.php
public function posts() { return $this->hasMany(Post::class); }
auth() helper or middleware:
Route::middleware(['auth'])->group(function () {
Route::resource('posts', PostController::class);
});
Service Providers (Replacing Symfony Services):
AppServiceProvider:
public function register() {
$this->app->singleton('postRepository', function () {
return new \App\Repositories\PostRepository;
});
}
$this->app->bind(
\App\Contracts\PostRepository::class,
\App\Repositories\EloquentPostRepository::class
);
Events (Replacing Symfony Events):
php artisan make:event PostCreated
// app/Providers/EventServiceProvider.php
protected $listen = [
\App\Events\PostCreated::class => [
\App\Listeners\NotifyPostAuthor::class,
],
];
event(new PostCreated($post));
Symfony-Specific Assumptions:
@ORM\*, which Laravel’s Eloquent does not support. Replace with Eloquent attributes (PHP 8+) or fluent methods:
// Symfony (Doctrine)
/** @ORM\ManyToOne(targetEntity="User") */
private $user;
// Laravel (Eloquent)
public function user() { return $this->belongsTo(User::class); }
{% extends %} or {{ asset() }} in templates. Use Blade:
@extends('layouts.app')
@section('content')
<img src="{{ asset('storage/' . $post->image) }}">
@endsection
Database Schema Mismatches:
User extends Symfony’s User class. In Laravel, use:
// app/Models/User.php
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable { ... }
user_id vs. author_id).Routing Conflicts:
Route::get('/posts/{post:slug}', [PostController::class, 'show']);
Route::name('posts.show')->get('/posts/{post}', ...);
Dependency Injection:
ContainerAware or autowiring via annotations. Laravel uses:
public function __construct(private PostRepository $posts) {}
new instantiations; use dependency injection.File Upload Paths:
vich_uploader.destination. In Laravel, configure spatie/laravel-medialibrary in .env:
MEDIA_LIBRARY_DISK=public
public/storage is symlinked:
php artisan storage:link
Pagination Quirks:
Knp\Component\Pager\PaginatorInterface. LaravelHow can I help you explore Laravel packages today?