Symfony2 bundle specific Twig configuration/variables - symfony

I know that I can set Twig variables in my app/config/config.yml, however I want to set variables on a per bundle level (eg: Bundle/Resources/config/??.yml).
For example I want to include a bundle version identifier in the footer of my pages. I tried placing twig config into my bundles' services.yml however Symfony wasn't able to parse the configuration.
How can I achieve this?

I'm not sure how you could implement bundle specific configs for your example. The configs in bundles tend to be imported into the main config files which are now environment specific rather than bundle specific.
However, for your example I would just make a twig extension which returns the name of the bundle you're using. That way you can use it wherever you like in your templates. You can get the fully named route of your controller from the request, then just use preg matching to get the Bundle name. Something like the below should work:
public function getBundleName()
{
$pattern = "#([a-zA-Z]*)Bundle#";
$matches = array();
preg_match($pattern, $this->container->get('request')->get('_controller'), $matches);
return $matches[1];
}
In this example $this->container has been set in the constructor to be an instance of the container. If you are using another method to get the controller then substitute accordingly.

Related

Silverstripe 4 use additional custom HTMLEditorField

In Silverstripe 4 how can we use different HTMLEditor configs ?
I'd like to have two different HTMLEditorFields in the same environment.
One with all functionality and all Buttons.
And another one (MyCustomHTMLEditorField) with reduced functionality and e.g. only 3 buttons (underline, italic, bold).
How do you use ::set_active ?
How to extend HTMLEditorConfig ?
Yes, i've read the documentation but How can this be archived?
There can be multiple configs, which should always be created / accessed using HtmlEditorConfig::get(). You can then set the currently active config using set_active().
Can you provide an Example?
Any help welcome.
The documentation at https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/ goes to length about how to define and use HTMLEditorConfig sets.
HTMLEditorConfig::set_active() is really for if you're intending to set an editor for use in multiple HTMLEditorFields in a given form or admin section, or to override the config for all admin sections. It more-or-less sets the 'default' config. That won't be so useful in your case, as it sounds like you want to set a configuration for a given HTMLEditorField.
Setting configuration
This is detailed in the documentation at https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/#adding-and-removing-capabilities
Usually this is done in your _config.php (or in some separate class which then gets called from _config.php - unless you only need it in a very specific section, in which case you could set this up or call your special class from that admin's init() method).
The examples in the documentation here modify the default ('cms') config. This is useful if you want to modify the configuration that is used by default. So do this for your config that you've referred to as having "all functionality and all Buttons".
Setting up a new HTMLEditorConfig
Calling HTMLEditorConfig::get($configName) will get the existing config based on the name you pass it - but if there is no existing config, it will create a new one. So you could call $customConfig = HTMLEditorConfig::get('some-custom-config') - now your $customConfig variable holds a new configuration that you can configure however you so choose (insert buttons, enable plugins, define whitelisted elements, etc).
Using configuration
This is discussed in the documentation here: https://docs.silverstripe.org/en/4/developer_guides/forms/field_types/htmleditorfield/#specify-which-configuration-to-use
I've already mentioned the set_active() - if you're going to set up multiple HTMLEditorFields in a form for example you can use that in your getCMSFields() method:
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', HMLEditorField::create('Content')); // This will use the default 'cms' config.
HTMLEditorConfig::set_active('some-custom-config');
$fields->addFieldToTab('Root.Main', HMLEditorField::create('OtherContent')); // This will use the 'some-custom-config' config that you defined.
// Don't forget to reset to the default.
HTMLEditorConfig::set_active('cms');
return $fields;
}
You can also, as explained in the docs, set your config by name for a given HTMLEditorField which is preferred if you're using a non-default for one one field.
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', HMLEditorField::create('Content')); // This will use the default 'cms' config.
$fields->addFieldToTab('Root.Main', HMLEditorField::create('OtherContent')->setEditorConfig('some-custom-config')); // This will use the 'some-custom-config' config that you defined.
return $fields;
}
Note that the syntax I used here is slightly different to the docs - this allows you to avoid passing in the second and third constructor arguments that you're not changing from the defaults. Keeps things a little tidier.
Disclaimer: All of the code above was written from memory, so it may need some tweaks to work correctly.

Symfony & TWIG: Route for Template directory not working fine

I'm new to Symfony and I have created many twig html templates and this function to route in my Controller:
/**
* #Route("/{path}")
*/
public function renderTemplate($path) {
return $this->render('/'.$path.'/index.html.twig');
}
?>
The renderTemplate() function works fine for all first level folders, but not for subdirectory files, because it seems like it interrups after a "/". I don't want to write dozens of new Route functions.
How can I implement all sites including subdirectories separated by "/"?
What is a safe practice and easy solution?
The structure of my twig templates folder is this:
Templates folder
#Routeis your URL, not your file path.
The default path in Symfony (3.4) is app/Ressources/view/
Thus, if you want to reach app/Ressources/view/default/index.html.twig, you will do this:
return $this->render('default/index.html.twig');
I just found the answer to be here in the Symfony documentation.
Apparently, you can allow "/" in your variable like this:
use Symfony\Component\Routing\Annotation\Route;
class DefaultController
{
/**
* #Route("/share/{token}", name="share", requirements={"token"=".+"})
*/
public function share($token)
{
// ...
}
}
I named all my twig templates "index.html.twig" and put them in the corresponding file path in my templates folder and now my function is working very smoothly for every site.
I may have to change it later to do individual requests, but it was a convienient short-term solution to be able to see all my pages with easy and nice-looking links and only one route function in my controller.

Symfony2. Enum: pls explain "You can register this type with Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType')"

I am trying to implemt the following instruction, as to have Enum type somehow
Shame on me, but I have not an idea on how/where I go to "register [the defined] type with Type::addType('<enummyfield>', 'MyProject\DBAL\<EnumMyfield>Type')".
EDIT Answer 1 helps. It seems I need too:
to move definition of EnumMyfield to directory MyBundle\Doctrine\DBAL\Types\Type (with appropriate use declarations)
to update app\config\config.yml with lines
types:
<myfield>: <mybundle>\Doctrine\DBAL\Types\Type\<EnumMyfield>Type
since I wish to have a Select on the Form side, to define:
->add('MyField','choice', array('label'=>'Select please', 'choices'=>array('A'=>'A','B'=>'B')), within my MyentityType\buildForm().
With respect to the last point, if I just use choices'=>array('A','B'), values for the select options are rendered as numbers (0,1), and I run into an error (I am not sure why)
your comments/advises are welcome
Just a recap, useful for others (maybe); I will highlight were you're blocked
Create a directory Doctrine\DBAL\Types
Define your new DBAL type there like shown into your link
Register it into your bundle main file (*) <--- this is what you're missing
Use it into entity definition
(*) You have a file inside your bundle named YourBundleNameBundle.php this file is used to register the bundle. If you want to register your custom type also, put inside this bundle the string Type::addType('enum', 'MyProject\DBAL\EnumType')".
So, something like
public function boot()
{
if (false === Type:hasType('enum')) {
$em = $this->container->get('doctrine.orm.entity_manager');
Type::addType('enum', 'Path\To\Bundle\Doctrine\DBAL\Types\EnumType');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enum','enum');
}
}
Don't forget the use statement
use Doctrine\DBAL\Types\Type;
at the top of the file

Create an Admin User with FosUserBundle

I try to create an Admin User with FOsUserBundle from command windows with the following command:
php app/console fos:user:create
In my project the Admin User extends other user with mandatory propriety. So, when I choose my username, mail and password, it tells me:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'latitude' cannot be null
How can I set the value "latitude" in my AdminUser? I also use PUGXMultiUserBundle.
Only possibile way to reach that to me is
1 - override the cli command of FOSUserBundle placed into Command/CreateUserCommand.php
2 - override the user create method of FOSUserBundle placed into Util/UserManipulator.php
// Command/CreateUserCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$latitude = $input->getOption('latitude'); //this will be your own logic add
$manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
$manipulator->create($username, $password, $email, $latitude, !$inactive, $superadmin);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
and
// Util/UserManipulator.php
public function create($username, $password, $email, $latitude, $active, $superadmin)
{
$user = $this->userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean) $active);
$user->setSuperAdmin((Boolean) $superadmin);
$user->setLatitude($latitude);
$this->userManager->updateUser($user);
return $user;
}
Of course when I say override i mean ... override :P So you haven't to modify FOSUserBundle original files (you know, it's dangerous for many reasons) but make your own files by making your bundle extended by FOSUserBundle
Are you wondering how to make your bundle extended by FOSUserBundle?
Into your bundle "mainfile" - is the one you use to register your bundle - just add this lines
public function getParent()
{
return 'FOSUserBundle';
}
Then you simply recreate the tree structure where your ovverride files lives into original bundle, into your custom bundle's Resources/ directory (same position, same file name, same annotations if any) and .... the magic can start :) (this is valid only for views, please pay attention!)
What "override" means?
Override means that you take an existent function, "shadow" it by redefining elsewhere (declare a function with the same name, no matter how many parameters it accept, no matter the type of paramenters since php doesn't support method overloading [except if you do some "hack"]) and then you can use it instead of the original one. This is a common technique for add extra functionalities to a function or to change the function itself.
Say that we have two classes, A and B with B that is a child class of A. Say also that A have a method called myMethod().
In B we can do something like
public function myMethod() {
parent::myMethod();
//add extra functionalities here
}
in that way we're adding extra functionalities as we're calling the parent ("original") method and then execute some extra functionalities
Whereas if in B we make something like
public function myMethod() {
//some code here, but not calling parent method
}
we're redefining the behaviour of myMethod()
How Symfony2 let me override methods?
As I said previously in my answer, you have to make your bundle a child of the bundle that containts the function(s) you're trying to override (in that case FOSUserBundle). Once you did it, use the Resources directory of your bundle to accomplish what you need. reproduce the "tree-folder-structure" of the original bundle (ie.: same names of the folders) until you reach the class that contains the function you need to override.
Follow your real example: you need to override execute() function contained in Command/CreateUserCommand.php. You have to create, into your bundle folder that path:
PathTo/YourCostumBundle/Command/
and place inside the file CreateUserCommand.php with the content I show you above.
If you don't understand where I find that path, please take a look to FOSUserBundle code and it will be absolutely clear!
Why is dangerous to modify the FOSUserBundle code directly?
Well, there's a lot of answer an critic point that I can show you. Choosing the main (not ordered for importance):
What if you need to update FOSUserBundle? You'll use composer and lost every modify that you made to FOSUserBundle code
What if you have more than one bundle into your project that need to use FOSUserBundle? Maybe the custom behaviour makes sense for a bundle but not for the other one. Costumizing the behaviour at local bundle level helps you to keep FOSUserBundle logic intact
What if you're developing a bundle that you want to share with other user? You need to force them to "take" your own costumized FOSUserBundle version and warn them about updating it
Finally: I perfeclty know that your entity isn't into FOSUserBundle, but I can bet that they extend FOSUserBundle base user so what I told above is applicable to your case.
Hope it's less fuzzy now :)
Documentation: http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-controllers
I always follow the pattern I learned in the symfony documentation itself:
php bin/console fos:user:create usertest mail#domain.com password
and sometimes I need change the "roles" on the table "fos_user"
then
a:0:{}
to
a:1:{i:0;s:10:"ROLE_ADMIN";}
After creating a user with:
bash-5.1# bin/console fos:user:create admin admin#mydomain.com password123
Promote the user with the ROLE_ADMIN role:
bash-5.1# bin/console fos:user:promote
Please choose a username:admin
Please choose a role:ROLE_ADMIN
Role "ROLE_ADMIN" has been added to user "admin". This change will not
apply until the user logs out and back in again.

Is a global variable for a Twig template available inside a Symfony2 controller?

A global variable for a Twig template can be defined inside the config.yml of a Symfony2 application as in the following:
twig:
globals:
var_name: var_value
Hence, in each Twig template the variable can be used as follows:
{{var_name}}
that will display
var_value
Do you know such a way to get the value of a global variable just inside a Symfony2 controller?
There doesn't seem to be a way to grab a particular value. But you can get the full array of globals from the twig service and then grab it's offset.
$twig = $this->container->get('twig');
$globals = $twig->getGlobals();
echo $globals['var_name'];
The right practice is to follow the official tutorial about Twig global variables in the Symfony's Cookbook. In practice, one should define a global variable that can be used in the controllers, e.g.:
; app/config/parameters.ini
[parameters]
my_global_var: HiAll
Then the variable is defined as global for the Twig templates
# app/config/config.yml
twig:
globals:
my_var: %my_global_var%
Hence, {{my_var}} will return HiAll but one should take care of the value once in the parameters.ini file.
So, the answer to the question is no! Or precisely, not in an effective way. MDrollette drawn a possible way!
I wasn't clear if you wanted to access the twig var in the controller, or just access a global var from the config. Here is how to access a global var from the config file...
You can place the value in the parameters section of the config..
parameters:
var_name: some_value
Now you can access it from the controller...
$value = $this->container->getParameter('var_name');
I think you'd better to use bundle configuration or DIC parameters for your value, and then add it to the twig globals (via your bundle extension class, for example), and not trying to do the opposite.

Resources