awaresoft/sonata-timeline-bundle
Installation via Composer (if not symlinked):
composer require awaresoft/sonata-timeline-bundle
Note: For local development, follow the README’s symlink instructions instead.
Enable the Bundle in config/bundles.php:
return [
// ...
Awaresoft\SonataTimelineBundle\SonataTimelineBundle::class => ['all' => true],
];
Basic Configuration in config/packages/sonata_timeline.yaml:
sonata_timeline:
driver: doctrine_orm # or 'doctrine_mongodb'
model_manager: default
models:
event: App\Entity\Event
timeline: App\Entity\Timeline
Create Entities (if using Doctrine):
php bin/console make:entity Event
php bin/console make:entity Timeline
Extend SonataTimelineBundle\Model\EventInterface and TimelineInterface in your entities.
First Use Case:
// In a controller/service
$timeline = $this->getDoctrine()->getRepository(Timeline::class)->findOneBy(['slug' => 'project-x']);
$events = $timeline->getEvents()->toArray(); // Load events for the timeline
Creating Events:
$event = new Event();
$event->setTitle('Project Kickoff')
->setStartDate(new \DateTime('2023-10-01'))
->setEndDate(new \DateTime('2023-10-07'))
->setTimeline($timeline);
$entityManager->persist($event);
$entityManager->flush();
Bulk Operations:
Use SonataTimelineBundle\Manager\EventManager to batch-create/update events:
$eventManager = $this->container->get('sonata.timeline.manager.event');
$eventManager->createMultiple($eventsArray, $timeline);
Embedding in Twig:
{% render timeline(timeline, {
'height': '600px',
'zoomable': true,
'editable': current_user.can_edit
}) %}
Requires JavaScript initialization (see SonataAdminBundle for similar patterns).
Customizing Renders:
Override the default template at templates/sonata_timeline/default/index.html.twig.
# config/packages/sonata_admin.yaml
sonata_admin:
options:
timeline:
enabled: true
manager_type: sonata.timeline.manager.event
Expose Event and Timeline as admin entities for CRUD.// src/EventListener/TimelineSyncListener.php
class TimelineSyncListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['onKernelView', 20],
];
}
public function onKernelView(GetResponseForControllerResultEvent $event)
{
$timeline = $event->getControllerResult();
if ($timeline instanceof Timeline) {
$event->getRequest()->attributes->set('sonata_timeline_data', $timeline->getEvents());
}
}
}
Doctrine vs. MongoDB:
Timeline and Event entities implement SonataTimelineBundle\Model\MongoDB\TimelineInterface and EventInterface.sonata.timeline.manager.mongodb_event as the manager service.Custom Event Types:
SonataTimelineBundle\Model\Event and override getType():
class CustomEvent extends Event
{
public function getType(): string
{
return 'custom';
}
}
{% set timelineTypes = {
'custom': {
'label': 'Custom Event',
'color': '#FF5733'
}
} %}
API Exposure:
$serializer = $this->container->get('serializer');
$timelineData = $serializer->serialize($timeline, 'json', [
'attributes' => ['groups' => ['timeline']],
]);
Caching:
$cache = $this->container->get('cache.app');
$cache->set('timeline_' . $timeline->getId(), $events, 3600, ['timeline_' . $timeline->getId()]);
Symlinking Issues:
composer dump-autoload is run after modifying the bundle.php bin/console cache:clear
php bin/console cache:pool:clear cache.array
Doctrine Proxy Problems:
Undefined index: id errors. Use ->toArray() or ->getValues() to materialize collections:
$events = $timeline->getEvents()->toArray(); // Force initialization
JavaScript Dependencies:
{{ parent() }}
{{ sonata_timeline_js() }} {# Add this in your base template #}
Timezone Handling:
$event->setStartDate($date->setTimezone(new \DateTimeZone('UTC')));
Backward Compatibility:
SonataTimelineBundle\Model\Event directly in production. Use composition or interfaces instead.Enable Debug Mode:
# config/packages/dev/sonata_timeline.yaml
sonata_timeline:
debug: true
Logs SQL queries and event lifecycle hooks.
Common Errors:
sonata_timeline.manager.event is autowired or configured in services.yaml.getEvents() returns a non-empty collection and the Twig template is rendered.Database Schema:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Custom Event Renderers:
SonataTimelineBundle\Twig\TimelineExtension:
// src/Twig/AppTimelineExtension.php
class AppTimelineExtension extends TimelineExtension
{
public function getEventTemplate(EventInterface $event)
{
return 'custom_timeline/event_' . $event->getType() . '.html.twig';
}
}
services.yaml:
services:
App\Twig\AppTimelineExtension:
tags: ['twig.extension']
arguments: ['@sonata.timeline.manager.event']
Event Validation:
Event entity:
use Symfony\Component\Validator\Constraints as Assert;
class Event
{
/**
* @Assert\NotBlank
* @Assert\Length(min=3)
*/
private $title;
}
Event Subscribers:
sonata.timeline.event.pre_persist and sonata.timeline.event.pre_remove:
$eventDispatcher->addListener(
'sonata.timeline.event.pre_persist',
function (Event $event) {
$event->setCreatedAt(new \DateTime());
}
);
Custom Timeline Providers:
SonataTimelineBundle\Provider\TimelineProviderInterface for dynamic timeline generation:
class DynamicTimelineProvider implements TimelineProviderInterface
{
public function getTimeline(string $slug): ?Timeline
{
// Fetch from API/database
}
}
services.yaml:
sonata.timeline.provider.dynamic:
class: App\Provider\DynamicTimelineProvider
tags: ['sonata.timeline.provider']
How can I help you explore Laravel packages today?