Since yesterday, I can't understand why i have this error on my Symfony website.
I have a service which depends on others. When i try to use and inject the Symfony doctrine entity manager i have errors. I can't find a way to do it :(
My config :
mycompany_jobs_bundle.processor.crm.product_matrix:
class: %mycompany_jobs_bundle.processor.crm.product_matrix.class%
parent: pim_base_connector.processor.product_to_flat_array
arguments:
- '#pim_catalog.repository.attribute'
- '#pim_catalog.localization.factory.date'
- '#doctrine.orm.default_entity_manager'
(I also tried 'doctrine.orm.entity_manager' instead of '#doctrine.orm.default_entity_manager' -> same results)
Then, in my service :
I add a "use Doctrine\ORM\EntityManager;" with the other "use" lines.
And this is my constructor :
... but i have this error :
Catchable Fatal Error: Argument 8 passed to
Mycompany\Bundle\JobsBundle\Processor\Mycompany\ProductWordMatrixProcessor::__construct()
must implement interface
Pim\Component\Catalog\Repository\AttributeRepositoryInterface,
instance of Doctrine\ORM\EntityManager given
Wherever i move my line "EntityManager $em" i have error with arguments position. What's wrong ? I can't understand ..
Thanks for your help
Edit : below the yml config of the parent service, pim_base_connector.processor.product_to_flat_array :
pim_base_connector.processor.product_to_flat_array:
class: %pim_base_connector.processor.product_to_flat_array.class%
arguments:
- '#pim_serializer'
- '#pim_catalog.manager.channel'
- '#pim_catalog.builder.product'
- ['pim_catalog_file', 'pim_catalog_image']
- %pim_catalog.localization.decimal_separators%
- %pim_catalog.localization.date_formats%
- '#akeneo_storage_utils.doctrine.object_detacher'
Try to move the EntityManaer as the last parameter of your constructor arguments like this:
public function __construct()
{
//.. others
AttributeRepositoryInterface $attributeRepository,
EntityManager $em
}
You need to maintain the order of your dependencies declared inside the configuration
You constructor has 10 arguments and all of them should be configured. You specified only 7. You have to specify last 3 as well and check the order. It's important.
Related
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'
I am working on migrating an existing Symfony 2.8 which I did not create. The previous developers are not available for questions.
Most of the code easy to understand, but at one point I simply cannot figure out how are why this works:
A controller/action parameter is automatically de-serialized from JSON data to a custom object. This is nothing special, I do not understand how/where the Symfony is told what to do. Form my point of view important config data is missing but it works anyway.
That's would be fine, but without understanding why it works in this case, I cannot figure out why it does not work anymore when migrating the project to Symfony 3.4...
Sorry for the (very) long question, but I tried different ways to solve the problem and answer the questions but they all resulted in different problems...
Using the following Bundles
sensio/framework-extra-bundle v3.0.29
friendsofsymfony/rest-bundle 2.4.0
jms/serializer 1.13.0
jms/serializer-bundle 1.5.0
Config:
// app/config/config.yml
sensio_framework_extra:
request: { converters: true }
fos_rest:
...
body_converter:
enabled: true
#jms_serializer: (not configured)
# ...
Code:
// src/AppBundle/Util/SortInfo.php
class SortInfo {
public $sortOrder;
public $sortBy;
}
// src/AppBundle/Resources/serializer/Util.SortInfo.yml
AppBundle\Util\SortInfo:
exclusion_policy: ALL
properties:
sortOrder:
type: string
expose: true
sortBy:
type: string
expose: true
// src/AppBundle/Controller/SortingController.php
class SortingController extends Controller {
...
/**
* #FOSRest\View()
*/
public function sortAction(SortInfo $sortInfo) {
$this->logger->info("sortAction");
$this->logger->info(" ".gettype($sortInfo)." -- ".get_class($sortInfo));
$this->logger->info(" ".$sortInfo->sortOrder." -- ".$sortInfo->sortBy);
...
}
}
That's it. After digging for some hours I could not find any explicit configuration that would tell the sortAction method to convert the JSON data from the request automatically. But it works.
A request with the following JSON content results in the following log output:
// JSON content
{"sortOrder":"ASC", "sortBy":"name"}
// Log output
sortAction
object -- AppBundle\Util\SortInfo
ASC -- name
Why does this work?
As said before this is fine, but the problem is, that the same code does not work with Symfony 3.4 and newer versions of FOSRest, ExtrasBundle and JMSSerializer:
sensio/framework-extra-bundle v5.2.4
friendsofsymfony/rest-bundle 2.5.0
jms/serializer 2.1.0
jms/serializer-bundle 3.0.0
A request with the same JSON data results in the following log output in `Symfony 3.4':
// Log output
sortAction
object -- AppBundle\Util\SortInfo
--
So although the SortInfo is created (not null), the sortBy and sortOrder properties are empty/null.
How can this be? I do not understand why the data is de-serialized in the first place, but how it is possible to create a SortInfo object without setting the properties is even more mysterious.
In Symfony 2.8 the Util.SortInfo.yml file is necessary for the process. Removing this files results in an exception:
Symfony\Component\HttpKernel\Exception\BadRequestHttpException: "You
must define a type for
AppBundle\Util\SortInfo::$sortBy."
at /.../vendor/friendsofsymfony/rest-bundle/Request/RequestBodyParamConverter.php
Here I do not understand why SortInfo::$sortBy is a problem but not SortInfo it self. Additionally removing the file in Symfony 3.4 does not change anything.
But at least this error message confirms, that the FOS RequestBodyParamConverter is involved in the process.
Following the Symfony docs it should be necessary to manually specify that the parameter that should be converted (although it works just fine without this config in Symfony 2.8):
/**
* #FOSRest\View()
* #ParamConverter("sortInfo", converter="fos_rest.request_body")
*/
public function sortAction(SortInfo $sortInfo) {
...
}
However, adding this config results in another error in Symfony 3.4:
Uncaught PHP Exception RuntimeException: "Converter
'fos_rest.request_body' does not support conversion of parameter
'$sortInfo'
Bottom line:
This is all very mysterious.
Why does it work without any problem in Symfony 2.8 although regarding to the docs essential config is missing (explicitly specify ParamConverter)
Why does it NOT work in Symfony 3.4?
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.)
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.
The default string normalization (provided by the Doctrine_Inflector::urlize() "sluggifier") isn't suitable for my project, so I need to utilize my own algorithm.
I set my schema up as follows:
MyObject:
actAs:
Sluggable:
fields: [name]
builder: array('TextUtility', 'normalize')
columns:
name: string(255)
And I added my utility class to the lib folder of my project (although I also tried the lib folder of an app) according to some instructions I found in another forum:
<?php
//lib/TextUtility.class.php
class TextUtility {
public static function normalize($str) {
/* ... */
return $str;
}
}
?>
When I run symfony doctrine:build --all I'm greeted by the following error:
Warning: call_user_func_array() expects parameter 1 to be a valid callback, function 'array('TextUtility', 'normalize')' not found or invalid function name in /symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Template/Listener/Sluggable.php on line 171
I assume I'm just putting my utility in the wrong place and it's not being loaded when needed. Am I putting it in the wrong place? Doctrine's documentation doesn't seem to mention the subject, unless I'm just looking at the wrong page.
arrays in YAML are defined other way:
MyObject:
actAs:
Sluggable:
builder: [TextUtility, normalize]