user2671968
user2671968

Reputation: 1

symfony 2 Updating color schemes dynamically

I'm working in a project using Symfony 2, I'm using Assetic with rewrite and less filter, and it work fine, Now I'm planing to let administrator (connected user) to controle some features in css like font and main color. The problem that I'm facing is :

- how can I proceed to integrate these css changes from entity to the css management

Upvotes: 0

Views: 1240

Answers (2)

Marcel Burkhard
Marcel Burkhard

Reputation: 3523

As suggested by Steffen you should put the dynamic CSS in a Twig template.

But now you might suffer from that part of the css being a full request to a symfony application instead of a css (HTTP 302 and such) which increases server load.

Thats why I would advise you to do 3 things (you can skip step 2 if your css doesn't change without interaction, e.g. date based):

  • Implement a service which caches the current output to e.g. web/additional.css.
  • Write and register a RequestListener to update the css regularly
  • Extend all controller actions that could introduce changes to the css with the service call

Example (assumes you use Doctrine and have an entity with some color information):

Service

<?php 
//Acme\DemoBundle\Service\CSSDeployer.php
namespace Acme\DemoBundle\Service;

use Doctrine\ORM\EntityManager;

class CSSDeployer
{
    /**
     * @var EntityManager
     */
    protected $em;

    /**
     * Twig Templating Service
     */
    protected $templating;

    public function __construct(EntityManager $em, $templating)
    {
        $this->em = $em;
        $this->templating = $templating;
    }

    public function deployStyle($filepath)
    {
        $entity = $this->em->getRepository('AcmeDemoBundle:Color')->findBy(/* your own logic here */);
        if(!$entity) {
            // your error handling
        }

        if(!file_exists($filepath)) {
            // your error handling, be aware of the case where this service is run the first time though
        }

        $content = $this->templating->render('AcmeDemoBundle:CSS:additional.css.twig', array(
            'data' => $entity
        ));

        //Maybe you need to wrap below in a try-catch block
        file_put_contents($filepath, $content);
    }
}

Service Registration

#Acme\DemoBundle\Resources\config\services.yml
services:
    #...
    css_deployer:
        class: Acme\DemoBundle\Service\CSSDeployer
        arguments: [ @doctrine.orm.entity_manager, @templating ]

RequestListener

<?php
//Acme\DemoBundle\EventListener\RequestListener.php
namespace Acme\DemoBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Debug\Exception\ContextErrorException;
use \DateTime;
use Doctrine\ORM\EntityManager;

class RequestListener
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var EntityManager
     */
    protected $em;

    public function __construct(ContainerInterface $container, $em)
    {
        $this->container = $container;
        $this->em        = $em;
    }

    /**
     * Checks filemtime (File modification time) of web/additional.css
     * If it is not from today it will be redeployed.
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        $kernel     = $event->getKernel();
        $container  = $this->container;

        $path = $container->get('kernel')->getRootDir().'/../web'.'/additional.css';

        $time = 1300000000;

        try {
            $time = @filemtime($path);
        } catch(ContextErrorException $ex) {
            //Ignore
        } catch(\Exception $ex) {
            //will never get here
            if(in_array($container->getParameter("kernel.environment"), array("dev","test"))) {
                throw $ex;
            }
        }

        if($time === FALSE || $time == 1300000000) {
            file_put_contents($path, "/*Leer*/");
            $time = 1300000000;
        }

        $modified   = new \DateTime();
        $modified->setTimestamp($time);
        $today      = new \DateTime();

        if($modified->format("Y-m-d")!= $today->format("Y-m-d")) {
            //UPDATE CSS
            try {                    
                $container->get('css_deployer')->deployStyle($path);
            } catch(\Exception $ex) {
                if(in_array($container->getParameter("kernel.environment"), array("dev","test"))){
                    throw $ex;
                }
            }
        } else {
            //DO NOTHING
        }
    }
}

RequestListener registration

#Acme\DemoBundle\Resources\config\services.yml
acme_style_update_listener.request:
    class: Acme\DemoBundle\EventListener\RequestListener
    arguments: [ @service_container, @doctrine.orm.entity_manager ]
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

Controller actions

public function updateAction()
{
    // Stuff
    $path = '....';
    $this->get('css_deployer')->deployStyle($path);
}

Hope this helps someone in the future.

Upvotes: 1

Steffen Ro&#223;kamp
Steffen Ro&#223;kamp

Reputation: 141

If you (or someone else) still need this:

I solved this by putting all generic CSS in a asset handled by Assetic like usual and putting the dynamic CSS generation in a Controller action and rendering the CSS with Twig.

Upvotes: 1

Related Questions