How define some PHP constant in the Symfony configuration? - php

this is my first post, so i will try to be clear
So i need to define some constants in the Symfony configuration (in a .yaml file, i guess)
I know i could define them throw public const MY_CONST but that is not what I want.
I guess this is what i need (the second part, i am not using Abstract controller as i am not in a controller)
https://symfony.com/doc/current/configuration.html#accessing-configuration-parameters
But I just can't get it to work. Could anyone help me, by giving me an exemple, or maybe an other way to do ?
Thanks guys.

The parameters you described can be used in the configuration defined as eg;
parameters:
the_answer: 42
You can then use these values in further configuration things (see below for example). Or if you want to handle these values in a controller you can (not recommended anymore) use $this->getParameter('the_answer') to get the value.
Binding arguments (recommended):
This approach wil bind values which you can then get (auto-magically injected) in a controller function/service by referencing the argument.
The values can range from simple scalar values to services, .env variables, php constants and all of the other things the configuration can parse.
# config/services.yaml
services:
_defaults:
bind:
string $helloWorld: 'Hello world!' # simple string
int $theAnswer: '%the_answer%' # reference an already defined parameter.
string $apiKey: '%env(REMOTE_API)%' # env variable.
Then these get injected in a service/controller function when we do something like:
public function hello(string $apiKey, int $theAnswer, string $helloWorld) {
// do things with $apiKey, $theAnswer and $helloWorld
}
More details and examples can be found in the symfony docs https://symfony.com/doc/current/service_container.html#binding-arguments-by-name-or-type
Inject into service (alternative)
You can also directly inject it into the defined service using arguments.
# config/services.yaml
services:
# explicitly configure the service
App\Updates\SiteUpdateManager:
arguments:
$adminEmail: 'manager#example.com'

Related

How to process %kernel.project_dir% from a .env variable?

I added this to my .env:
PHOTOS_DIR=%kernel.project_dir%/var/photos
Of course, when I try to retrieve the value of $_ENV['PHOTOS_DIR'], I get the raw string %kernel.project_dir%/var/photos.
But how can I get the value processed by the Symfony config processor, e.g. /my/project/var/photos?
EDIT:
I'm aware that it is simply possible to add this in services.yaml:
parameters:
photos_dir: '%kernel.project_dir%/var/photos'
But I would like to keep important config data in the .env file.
In order to expand %kernel.project_dir%, use %env(resolve:...) in parameters, e.g.:
parameters:
photos_dir: '%env(resolve:PHOTOS_DIR)%'
Your dotenv does not process the symfony yaml processor parameters.
Delete the %kernel.project_dir% from .env file and in your .yaml you need to bind a parameter like this:
photos_absolute_path: '%kernel.project_dir%%env(PHOTOS_DIR)%'
After that you can get the parameter from your container by the name of photos_absolute_path and it will point to the correct location
Using symfony parameters in .env-files is correct. Symfony will automatically resolve them.
After container will be compiled, you can get the real value if you bind it to a parameter.
.env
PHOTOS_DIR=%kernel.project_dir%/var/photos
services.yaml:
parameters:
photos_dir: '%env(PHOTOS_DIR)%'
Somewhere in your application:
$container->getParameter('photos_dir');

Symfony: Unknown "humanize_bytes" filter

In a Symfony 2.7 app, we have attempted to set up a humanize_bytes Twig filter in order to convert long numbers of bytes into human-readable form -- 10 MB, for example.
Within our HumanReadableBytesExtension.php file is the following:
public function getFilters() {
return [
new TwigFilter('humanize_bytes', [$this, 'getHumanReadableBytesFilter'])
];
}
... and in our services.yml file lies the following:
mycompany.cms.twig.extension.human_readable_bytes_extension:
class: MyCompany\TwigExtensions\HumanReadableBytesExtension
arguments:
- '#translator'
tags:
- {name: twig.extension}
... but we find that the getFilters() method is not getting called, and that when we try to call the filter in a Twig template, we get:
Unknown "humanize_bytes" filter.
Both files pass syntax validation. The cache has been cleared. Is there somewhere else where we should be registering this filter?
====
Edit: Here is the output of the app/console debug:container mycompany.cms.twig.extension.human_readable_bytes_extension command:
[container] Information for service
mycompany.cms.twig.extension.human_readable_bytes_extension Service Id
mycompany.cms.twig.extension.human_readable_bytes_extension Class
MyCompany\TwigExtensions\HumanReadableBytesExtension Tags
- twig.extension () Scope container Public yes Synthetic no Lazy no
Synchronized no Abstract no
You mentioned you are using an abstract class. Did you override the getName method in your HumanReadableBytesExtension ?
If two extensions have the same name, only one will be loaded, the second will be silently ignored.
I ultimately just took all of my changes and put them on a fresh feature branch. That "fixed" the problem, albeit in a very non-satisfactory way. (We never really did figure out what was going wrong.)

Symfony 3 own global configuration file

How i can create and use own global config with keys/values in symfony?
I was try set keys/values in parameters.yml under parameters line which been in this file after instalation and get it like $pageTitle = $this->getParameter('myKey'); and it works but i want own whole config file with structure for ex. $this->getParameter('myParameters.myKey') so:
I was created new file:
#app/config/myConfig.yml
myParameters:
myKey: myValue
In config.yml i added:
#app/config/config.yml
imports:
- { resource: myConfig.yml }
and in controller:
$pageTitle = $this->getParameter('myKey');
And i have exception:
FileLoaderLoadException in FileLoader.php line 118: There is no extension able to load the configuration for "inyconfig" (in....
EDIT
This example works but you must do one little change - myParameters change to parameters and everything is work like a charm.
You have to do a dependency injection e.g. BundleNameDependencieInjection related of your bundle and then create Configuration class that provide configure external dependence and/or external configurations
Have a look there http://symfony.com/doc/current/bundles/configuration.html#processing-the-configs-array
In parameters you can create some scalar or array variables that can be called in some circumstances in your case you may create an array with some range like that :
parameters:
# scalar
one.two.three: something
# array
oneBis:
twoBis:
threeBis: somethingBis
Use parameters instead of myParameters.
So, put in app/config/myConfig.yml:
parameters:
myKey: myValue

Symfony 2 - how to parse %parameter% in my own Yaml file loader?

I have a Yaml loader that loads additional config items for a "profile" (where one application can use different profiles, e.g. for different local editions of the same site).
My loader is very simple:
# YamlProfileLoader.php
use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Yaml\Yaml;
class YamlProfileLoader extends FileLoader
{
public function load($resource, $type = null)
{
$configValues = Yaml::parse($resource);
return $configValues;
}
public function supports($resource, $type = null)
{
return is_string($resource) && 'yml' === pathinfo(
$resource,
PATHINFO_EXTENSION
);
}
}
The loader is used more or less like this (simplified a bit, because there is caching too):
$loaderResolver = new LoaderResolver(array(new YamlProfileLoader($locator)));
$delegatingLoader = new DelegatingLoader($loaderResolver);
foreach ($yamlProfileFiles as $yamlProfileFile) {
$profileName = basename($yamlProfileFile, '.yml');
$profiles[$profileName] = $delegatingLoader->load($yamlProfileFile);
}
So is the Yaml file it's parsing:
# profiles/germany.yml
locale: de_DE
hostname: %profiles.germany.host_name%
At the moment, the resulting array contains literally '%profiles.germany.host_name%' for the 'hostname' array key.
So, how can I parse the % parameters to get the actual parameter values?
I've been trawling through the Symfony 2 code and docs (and this SO question and can't find where this is done within the framework itself. I could probably write my own parameter parser - get the parameters from the kernel, search for the %foo% strings and look-up/replace... but if there's a component ready to be used, I prefer to use this.
To give a bit more background, why I can't just include it into the main config.yml: I want to be able to load app/config/profiles/*.yml, where * is the profile name, and I am using my own Loader to accomplish this. If there's a way to wildcard import config files, then that might also work for me.
Note: currently using 2.4 but just about ready to upgrade to 2.5 if that helps.
I've been trawling through the Symfony 2 code and docs (and this SO question and can't find where this is done within the framework itself.
Symfony's dependency injection component uses a compiler pass to resolve parameter references during the optimisation phase.
The Compiler gets the registered compiler passes from its PassConfig instance. This class configures a few compiler passes by default, which includes the ResolveParameterPlaceHoldersPass.
During container compilation, the ResolveParameterPlaceHoldersPass uses the Container's ParameterBag to resolve strings containing %parameters%. The compiler pass then sets that resolved value back into the container.
So, how can I parse the % parameters to get the actual parameter values?
You'd need access to the container in your ProfileLoader (or wherever you see fit). Using the container, you can recursively iterate over your parsed yaml config and pass values to the container's parameter bag to be resolved via the resolveValue() method.
Seems to me like perhaps a cleaner approach would be for you to implement this in your bundle configuration. That way your config will be validated against a defined structure, which can catch configuration errors early. See the docs on bundle configuration for more information (that link is for v2.7, but hopefully will apply to your version also).
I realise this is an old question, but I have spent quite a while figuring this out for my own projects, so I'm posting the answer here for future reference.
I tried a lot of options to resolve %parameter% to parameters.yml but no luck at all. All I can think of is parsing %parameter% and fetch it from container, no innovation yet.
On the other hand I don't have enough information about your environment to see the big picture but I just come up with another idea. It can be quite handy if you declare your profiles in your parameters.yml file and load it as an array in your controller or service via container.
app/config/parameters.yml
parameters:
profiles:
germany:
locale: de_DE
host_name: http://de.example.com
uk:
locale: en_EN
host_name: http://uk.example.com
turkey:
locale: tr_TR
host_name: http://tr.example.com
You can have all your profiles as an array in your controller.
<?php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
$profiles = $this->container->getParameter('profiles');
var_dump($profiles);
return $this->render('AcmeDemoBundle:Default:index.html.twig');
}
}
With this approach
you don't have to code a custom YamlLoader
you don't have to worry about importing parameters into other yml files
you can have your profiles as an array anytime you have the $container in your hand
you don't have to load/cache profile files one by one
you don't have to find a wildcard file loading solution
If I got your question correctly, this approach can help you.

Symfony 2 odbc component

Just configuring my Standard Symfony2 edition to be used with the odbc driver. I need that for the Teradata connection.
I completely don't need any ORM tools, I will only use it to return the results from the Teradata Stored Procedure or complex query.
Currently it works in the procedural PHP code by following few simple steps:
- $conn = odbc_connect(HOST, USER, PASSWORD)
- $stmt = odbc_prepare($conn, $query)
- $params = array(1, 2, 3)
- odbc_execute($stmt, $params)
- next just fetch results using odbc_fetch_array($stmt)
Just thinking now about how and where to implement this in the Symfony2 MVC stack according to the Sf2 best practices... Perhaps a separate service?
Will only mention that the ease of use for fresh developers is a priority.
Thanks in advance for any help!
From what you describe I would suggest creating a service which, instead of using global constants receives HOST, USER and PASSWORD via Service Container, i.e. you store that information in your parameters.yml, create a service with these parameters in your bundle's service.yml and finally you create your Service-class which basically just wraps your odbc-calls.
This way you can keep the sensitive data (user, password) out of your git-repo, assuming you are not tracking parameters.yml as is suggested in Symfony's documentation and you can easily access your service from everywhere where you have access to the Service Container like this:
$this->getContainer()->get('acme_demo.teradata_service')
parameters.yml:
parameters:
teradata_host: localhost
teradata_user: username
teradata_password: password
Acme\DemoBundle\Resources\config\services.yml:
services:
acme_demo.teradata_service:
class: Acme\DemoBundle\Service\TeradataService
arguments:
- %teradata_host%
- %teradata_user%
- %teradata_password%
Acme\DemoBundle\Service\TeradataService:
class TeradataService
{
public function __construct($host, $user, $password)
...
}
You could even go further and make the teradata service private in your service.yml and then just create other services which access your TeradataService. This way you can make sure, that deleopers do not interfere with the service directly, but only via ObjectManagers.
Acme\DemoBundle\Resources\config\services.yml:
services:
acme_demo.teradata_service:
public: false
class: Acme\DemoBundle\Service\TeradataService
arguments:
- %teradata_host%
- %teradata_user%
- %teradata_password%
acme_demo.another_service:
class: Acme\DemoBundle\Service\ServiceAccessingTeradata
arguments:
- #acme_demo.teradata_service
This way your services are not bound to your teradata-connection directly, which makes it easier to replace Acme\DemoBundle\Service\TeradataService with something else.

Categories