binsoul/symfony-bundle-content
Installation:
composer require binsoul/symfony-bundle-content
Ensure your project uses Symfony (this bundle is Symfony-specific, but Laravel can adapt concepts).
Bundle Registration:
Add the bundle to config/bundles.php (Symfony) or manually integrate its core logic (e.g., content management) into Laravel’s service container.
First Use Case:
AppKernel.php or config/bundles.php.ContentManager (or equivalent) to replicate its functionality using Laravel’s ServiceProvider and Facade patterns. For example:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('content.manager', function ($app) {
return new \Binsoul\ContentBundle\Manager\ContentManager();
});
}
Key Classes to Explore:
ContentManager: Core logic for content operations.ContentInterface: Contract for content entities (useful for defining Laravel models).EventDispatcher: For extending content lifecycle (map to Laravel’s Events system).Content Management:
ContentManager to CRUD content entities (e.g., Article, Page).Content) with fields like title, body, slug, and published_at.// app/Services/ContentService.php
class ContentService {
protected $manager;
public function __construct(ContentManager $manager) {
$this->manager = $manager;
}
public function getPublishedContents() {
return $this->manager->findBy(['published' => true]);
}
}
AppServiceProvider and use it in controllers.Event-Driven Extensions:
EventDispatcher for hooks (e.g., ContentCreateEvent). In Laravel, replace with:
// Listen to content creation
event(new ContentCreated($content));
EventServiceProvider:
protected $listen = [
'ContentCreated' => [
'NotifyContentTeam',
],
];
Dependency Injection:
ContentManager into controllers/services:
public function show(ContentManager $manager, $slug) {
$content = $manager->findOneBy(['slug' => $slug]);
return view('content.show', compact('content'));
}
Configuration:
Configuration component. In Laravel, replicate in config/content.php:
return [
'default_locale' => 'en',
'storage' => 'database', // or 'filesystem'
];
Database: The bundle likely uses Doctrine ORM. In Laravel, use Eloquent migrations:
php artisan make:migration create_contents_table
Define fields matching the bundle’s ContentInterface.
APIs: If the bundle fetches remote content, adapt to Laravel’s Http client or Guzzle:
$client = new \GuzzleHttp\Client();
$response = $client->get('https://api.example.com/content');
Caching: Use Laravel’s cache (e.g., Cache::remember) to store fetched content:
$content = Cache::remember("content_{$slug}", now()->addHours(1), function () use ($manager, $slug) {
return $manager->findOneBy(['slug' => $slug]);
});
Symfony-Specific Dependencies:
EventDispatcher, DependencyInjection). In Laravel:
EventDispatcher with Laravel’s Event system.Container instead of Symfony’s ContainerInterface.SymfonyAdapter service).Doctrine ORM:
DoctrineToEloquentAdapter to translate queries:
class DoctrineToEloquentAdapter {
public function findBy(array $criteria) {
return Content::where($criteria)->get();
}
}
Configuration Overrides:
Configuration class may not play nicely with Laravel’s config() helper.AppServiceProvider:
$this->app->singleton('content.config', function () {
return array_merge(
require __DIR__.'/../config/content.php',
$this->app['config']['content.custom'] ?? []
);
});
Event Naming Collisions:
ContentCreateEvent) may conflict with Laravel’s Creating events.Binsoul\ContentCreated) or namespace them:
event(new \App\Events\Binsoul\ContentCreated($content));
Testing:
TestCase. In Laravel:
PHPUnit with Laravel’s RefreshDatabase trait.ContentManager in tests:
$manager = Mockery::mock(\Binsoul\ContentBundle\Manager\ContentManager::class);
$manager->shouldReceive('findOneBy')->andReturn($content);
$this->app->instance('content.manager', $manager);
Log Symfony Exceptions:
try {
$content = $manager->findOneBy(['slug' => $slug]);
} catch (\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException $e) {
Log::error('ContentManager not bound: '.$e->getMessage());
abort(500);
}
Dump Container Bindings:
ContentManager is properly bound:
dd($this->app->bound('content.manager') ? $this->app->make('content.manager') : 'Not bound');
Configuration Validation:
config/content.php against the bundle’s expected structure:
if (!isset(config('content.storage'))) {
throw new \RuntimeException('Content storage not configured.');
}
Custom Content Types:
ContentInterface to add fields (e.g., VideoContent):
interface VideoContent extends ContentInterface {
public function getEmbedUrl();
}
class Content extends Model {
public function getContentType() {
return $this->type;
}
}
Storage Backends:
// app/Services/ContentStorage.php
class ContentStorage {
public function save($content) {
// Use Laravel's Filesystem or cache
Storage::disk('s3')->put("content/{$content->slug}.json", $content);
}
}
Validation:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($data, [
'title' => 'required|max:255',
'body' => 'required',
]);
API Resources:
Resource classes:
class ContentResource extends JsonResource {
public function toArray($request) {
return [
'title' => $this->title,
'slug' => $this->slug,
'published_at' => $this->published_at->toDateTimeString(),
];
}
}
How can I help you explore Laravel packages today?