While working on a Symfony2 project yesterday, I realized I needed a better way to format dates in my templates. The reason behind this was the fact that my MongoDB document entities contained date values that were either null or DateTime instances. This entailed using a bunch of if statements for extra checks that made template code unnecessarily verbose.
My solution was to create a template helper in an application specific framework bundle that I had created previously to contain all common assets and other necessary common resources.
Create a Helper directory in the framework bundle directory and create a DateHelper class:
src/Acme/FrameworkBundle/Helper/DateHelper.php
namespace Acme\FrameworkBundle\Helper;
use Symfony\Component\Templating\Helper\Helper;
class DateHelper extends Helper
{
protected $options;
public function __construct(array $options)
{
$this->options = $options;
}
public function getName()
{
return 'date';
}
public function format($date, $detailed = false)
{
if (!empty($date)) {
if ($date instanceof \DateTime) {
if ($detailed === true) {
return $date->format($this->getOption('detailed_format'));
} else {
return $date->format($this->getOption('default_format'));
}
}
}
return null;
}
protected function getOption($name)
{
if (array_key_exists($name, $this->options)) {
return $this->options[$name];
}
throw new Exception('Options does not exist');
}
}
Define the configuration options for your helper:
src/Acme/FrameworkBundle/DependencyInjection/Configuration.php
namespace Acme\FrameworkBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('acme_framework');
$rootNode->children()
->arrayNode('helper')
->isRequired()
->children()
->arrayNode('date')
->isRequired()
->children()
->scalarNode('default_format')->defaultValue('Y-m-d')->cannotBeEmpty()->end()
->scalarNode('detailed_format')->defaultValue('Y-m-d H:i:s')->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
Add the new configuration section that you have defined for your helper to your config.yml:
app/config/config.yml
acme_framework:
helper:
date:
default_format: "Y-m-d"
detailed_format: "Y-m-d H:i:s"
The above approach is a very simplistic approach and would not be the correct one if you are dealing with localization. However, in my case, this is more than enough.
Add the necessary code to your extension class to load your new configuration:
src/Acme/FrameworkBundle/DependencyInjection/AcmeFrameworkExtension.php
namespace Acme\FrameworkBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class AcmeFrameworkExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('acme_framework.helper.date', $config['helper']['date']);
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
}
}
The next step is to define our service and tag it as a helper:
src/Acme/FrameworkBundle/Resources/config/services.xml
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="acme_framework.helper.date" class="Acme\FrameworkBundle\Helper\DateHelper">
<tag name="templating.helper" alias="date" />
<argument>%acme_framework.helper.date%</argument>
</service>
</services>
</container>
And that is pretty much it. You can now call your helper in your templates like this:
echo $view['date']->format($activity->getStartedAt());