Installation Add the bundle via Composer:
composer require confl1kt/news-bundle
Enable it in config/bundles.php:
return [
// ...
Confl1kt\NewsBundle\Confl1ktNewsBundle::class => ['all' => true],
];
Database Migrations Run migrations to create required tables:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First News Entry Create a news entry via CLI (if using Sonata Admin):
php bin/console sonata:news:create
Or manually via Doctrine:
$news = new \Confl1kt\NewsBundle\Entity\News();
$news->setTitle('First Post');
$news->setContent('Hello, world!');
$em->persist($news);
$em->flush();
Routing & Templates
Ensure sonata_news routes are imported in config/routes.yaml:
sonata_news:
resource: "@Confl1ktNewsBundle/Resources/config/routing/sonata_news.xml"
prefix: /news
Override default templates in templates/Confl1ktNewsBundle/ if needed.
Inject the repository into a controller:
use Confl1kt\NewsBundle\Repository\NewsRepository;
class HomeController extends AbstractController
{
public function index(NewsRepository $newsRepo)
{
$latestNews = $newsRepo->findLatest(5); // Custom query method
return $this->render('home/index.html.twig', [
'news' => $latestNews,
]);
}
}
// config/packages/sonata_admin.yaml
sonata_admin:
options:
html5_validate: true
managers:
news:
label: News
class: Confl1kt\NewsBundle\Admin\NewsAdmin
controller: sonata.admin.controller.crud
NewsAdmin class:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('title', 'text', ['label' => 'Title'])
->add('content', 'sonata_media_type', ['provider' => 'sonata.media.provider.file']);
}
Extend the NewsRepository for reusable queries:
// src/Repository/CustomNewsRepository.php
class CustomNewsRepository extends ServiceEntityRepository
{
public function findByCategory(string $category, int $limit = 10)
{
return $this->createQueryBuilder('n')
->where('n.category = :category')
->setParameter('category', $category)
->orderBy('n.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult();
}
}
Bind it in services.yaml:
services:
App\Repository\CustomNewsRepository:
parent: Confl1kt\NewsBundle\Repository\NewsRepository
tags: ['doctrine.repository_service']
Hook into lifecycle events (e.g., publish/unpublish):
// src/EventListener/NewsListener.php
class NewsListener implements NewsEvents
{
public function onNewsPublish(NewsEvent $event)
{
// Send notification, log, etc.
}
}
Register in services.yaml:
services:
App\EventListener\NewsListener:
tags:
- { name: kernel.event_listener, event: news.publish, method: onNewsPublish }
Use Symfony’s JsonResponse or API Platform:
#[Route('/api/news', name: 'api_news', methods: ['GET'])]
public function getNews(NewsRepository $newsRepo): JsonResponse
{
$news = $newsRepo->findLatest();
return $this->json($news);
}
Attach media (images, files) to news:
$news->setMedia([
new \Sonata\MediaBundle\Entity\Media(),
]);
Restrict news creation to authenticated users:
# config/packages/security.yaml
access_control:
- { path: ^/news/create, roles: ROLE_USER }
Use Symfony’s translation system for multilingual content:
{{ news.title|trans }}
Define translations in translations/messages.en.yaml:
news:
title: 'Hello, %name%!'
Cache news lists for performance:
$cache = $this->get('cache.app');
$key = 'news_latest_' . $limit;
$news = $cache->get($key, function() use ($newsRepo, $limit) {
return $newsRepo->findLatest($limit);
});
Missing Dependencies
composer require sonata-project/admin-bundle doctrine/orm
Route Conflicts
sonata_news routes don’t clash with existing routes. Use prefix in routing.yaml:
sonata_news:
prefix: /blog
Template Overrides
templates/Confl1ktNews/ instead of templates/Confl1ktNewsBundle/). Fix: Use the exact bundle namespace in the path.Media Handling
sonata.media.provider.file is configured in config/packages/sonata_media.yaml:
sonata_media:
providers:
file:
resizer: sonata.media.resizer.square
Permission Issues
createdAt/updatedAt timestamps by default. Add lifecycle callbacks:
// src/Entity/News.php
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class News
{
#[ORM\PrePersist]
public function setCreatedAt(): void
{
$this->createdAt = new \DateTime();
}
}
Doctrine Queries
Enable SQL logging in .env:
DOCTRINE_DDL_AUTO_CREATE_SCHEMA=true
DOCTRINE_DDL_AUTO_COMPLETE_SCHEMA=true
APP_DEBUG=true
Check logs in var/log/dev.log.
Admin Panel Issues Clear cache after changes:
php bin/console cache:clear
php bin/console sonata:admin:validate
Event Dispatching
Verify events are registered in services.yaml and the listener implements the correct interface (e.g., NewsEvents).
Custom Fields
Add custom fields (e.g., slug, excerpt) to the News entity:
#[ORM\Column(length: 255, unique: true)]
private ?string $slug = null;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $excerpt = null;
Update the NewsAdmin to include them in forms.
Soft Deletes Implement soft deletes for news:
#[ORM\Column(type: 'boolean')]
private bool $isPublished = false;
#[ORM\PreRemove]
public function setIsPublishedToFalse(): void
{
$this->isPublished = false;
}
SEO Optimization
Use Metadata from sonata-seo-bundle:
$news->setMetaTitle('Latest News');
$news->setMetaDescription('Stay updated with our blog.');
Testing
Use Symfony’s WebTestCase to test news routes:
public function testNewsListing()
{
$client = static::createClient();
$client->request('GET', '/news');
$this->assertResponseIsSuccessful();
}
Performance
$paginator = $this->createQueryBuilder('n')
How can I help you explore Laravel packages today?