简体   繁体   中英

Customize UI of whole symfony website with one form

I'm trying to let a certain type of user customize the UI of a symfony website. I'm a little bit lost on how can I override the css properties when the form is submitted. Also the data will be saved in AWS S3 cloud. So I will need to create a connector service for this.

I've created a controller, entity, repository and template for this feature.

Here is the controller :

<?php

namespace App\Controller;

use App\Entity\OrganizationCustomization;
use App\Forms\CustomizationFormType;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class OrganizationCustomizationController extends AbstractController
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @Route("/organization/customization", name="organization_customization")
     *
     * @param Request $request
     *
     * @return Response
     */
    public function buildForm(
        Request $request
    ) {
        //If user do not have permission we redirect him to the dashboard
        if (!$this->isGranted('ROLE_COMPANY_MANAGER', '') || !$this->isGranted('ROLE_SUPERADMIN', '')) {
            $this->redirectToRoute('dashboard');
        }
        //Calling the organization customization form
        $organizationCustomization = new OrganizationCustomization();
        $form = $this->createForm(CustomizationFormType::class, $organizationCustomization);

        //Get companyId of the user to set it in OrganizationCustomization entity
        $companyId = $this->getUser()->getCompany()->getId();

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $organizationCustomization = $form->getData();
            $organizationCustomization->setId($companyId);
            $organizationCustomization->setIsActive(true);

            /** @var UploadedFile $logoFile */
            $logoFile = $form['logoFile']->getData();

            if ($logoFile) {
                $originalFilename = pathinfo($logoFile->getClientOriginalName(), PATHINFO_FILENAME);
                // this is needed to safely include the file name as part of the URL
                $safeFilename = transliterator_transliterate(
                    'Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()',
                    $originalFilename
                );
                $newFilename = $safeFilename.'-'.uniqid().'.'.$logoFile->guessExtension();
                // Move the file to the directory where images are stored
                try {
                    $logoFile->move(
                        $this->getParameter('company_logo_directory'),
                        $newFilename
                    );
                } catch (FileException $e) {
                    // handle exception if something happens during file upload

                    $this->logger->info('File upload has failed '.$e);
                }
                // updates the 'logoFilename' property to store the PDF file name
                // instead of its contents
                $organizationCustomization->setLogoFile($newFilename);
                dump($organizationCustomization);
            }
        }

        return $this->render('organization_customization/index.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

Here is the entity :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\OrganizationCustomizationRepository")
 */
class OrganizationCustomization
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=7, nullable=true)
     */
    private $backgroundColor;

    /**
     * @ORM\Column(type="string", length=7, nullable=true)
     */
    private $fontColor;

    /**
     * @ORM\Column(type="string", length=7, nullable=true)
     */
    private $baseSiteColor;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $logoFile;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isActive;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setId(?int $id): self
    {
        $this->id = $id;

        return $this;
    }

    public function getBackgroundColor(): ?string
    {
        return $this->backgroundColor;
    }

    public function setBackgroundColor(?string $backgroundColor): self
    {
        if (true === \mb_strpos($backgroundColor, '#')) {
            $this->backgroundColor = $backgroundColor;
        }

        return $this;
    }

    public function getFontColor(): ?string
    {
        return $this->fontColor;
    }

    public function setFontColor(?string $fontColor): self
    {
        if (true === \mb_strpos($fontColor, '#')) {
            $this->fontColor = $fontColor;
        }

        return $this;
    }

    public function getBaseSiteColor(): ?string
    {
        return $this->baseSiteColor;
    }

    public function setBaseSiteColor(?string $baseSiteColor): self
    {
        if (true === \mb_strpos($baseSiteColor, '#')) {
            $this->baseSiteColor = $baseSiteColor;
        }

        return $this;
    }

    public function getLogoFile(): ?string
    {
        return $this->logoFile;
    }

    public function setLogoFile(?string $logoFile): self
    {
        $this->logoFile = $logoFile;

        return $this;
    }

    public function getIsActive(): ?bool
    {
        return $this->isActive;
    }

    public function setIsActive(bool $isActive): self
    {
        $this->isActive = $isActive;

        return $this;
    }
}

And here is my template:

{% block headtop %}
    <title>{% block title %}Harmonie Technologie{% endblock %}</title>
    {% include "head.html.twig" %}
{% endblock headtop %}
{% include "css.html.twig" %}

<body>
    {% block body %}

        {#{{ form(form.backgroundColor, {attr: {class: 'customize-background-color'}}) }}
        {{ form(form.fontColor) }}
        {{ form(form.baseSiteColor) }}
        {{ form(form.logoFile) }}#}
        {{ form(form) }}

{% endblock %}
</body>

For now I'm getting the right values when I submit the form but i'm trying to override the templates/css.html.twig that is only containing this :

<link href="{{absolute_url("/bootstrap/css/bootstrap.min.css")}}" rel="stylesheet"/>
<link href="{{absolute_url("/fontawesome-5.6.3/css/all.min.css")}}" rel="stylesheet">
<link href="{{absolute_url("/jquery-ui-1.12.1.custom/jquery-ui.min.css")}}" rel="stylesheet">
<link href="{{absolute_url("/jquery-ui-1.12.1.custom/jquery-ui.structure.min.css")}}" rel="stylesheet">
<link href="{{absolute_url("/css/riskandme.css")}}" rel="stylesheet">
<link href="{{absolute_url('/css/bootstrap-datetimepicker.css')}}" rel="stylesheet"/>

Thank you a lot for you attention and help.

If you want to keep user preferences you need to persist it in database. There are some possibilities.

@Wouter J used that:

1)Create a stylesheet, for instance styles.css.twig and put the content there. For instance:

.user-color{
    color: {{ user_color }};
}

Now, create a class which renders this file and saves it somewhere:

class TemplateRenderer
{
    protected $basepath;
    protected $templating;
    protected $parameters = array();

    public function __construct($templating, $basepath, $styleseheetpath)
    {
        $this->basepath = $basepath; /* "%kerel.base_path" parameter */
        $this->templating = $templating; /* "twig" service */
        $this->stylesheetpath = $stylesheetpath; /* custom defined parameter */
    }

    public function setParam($id, $value)
    {
        $this->parameters[$id] = $value;
    }

    public function render()
    {
        file_put_contents(
            $this->basepath.'/web/assets/css/styles.css',
            $this->templating->render(
                $this->stylesheetpath,
                $this->parameters
            )
        );
    }
}

Register this class as a service and register it as an after event listener ( http://symfony.com/doc/current/cookbook/event_dispatcher/before_after_filters.html ).

From your controller (or from the event config file using method injection), you can call the setParam method to set a variable.

Inside your base html file, you can include this file using it's path (now, web/assets/css/styles.css).

Please note that the code is an example. Some error handling and caching is definitely needed to make this usable in production.

Source: Symfony2: Use Twig variable in stylesheet

2)You can use the twig "include with":

 {% include 'style.css' with {'color': user.color} %}

Source: https://twig.symfony.com/doc/2.x/tags/include.html

3)You could use different preformatted css files:

For example you could have a field "ui_color" in database. The user can submit a form and choose "green" or "orange".

You have two css files, one is "green-theme.css", the other one is"orange-theme.css".

Then you call it in your twig file like:

{% include myUser.ui_color ~ ".css" %}

4) you could use inline css in your twig file, and use twig variables to modify somes values in it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM