Symfony 3.4 vendor autowire - php

I've got a problem with symfony 3.4 I'm stuck with. I think i'm not getting symfony autowire right, but I can't find what's causing the error.
I have a fresh installation of symfony with only one addtional package installed: league/tactician-bundle
I try to inject it in constructor of DefaultController in the folowing way:
/**
* #var CommandBus
*/
private $bus;
public function __construct(CommandBus $bus)
{
$this->bus = $bus;
}
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
dump($this->bus);die;
}
My services.yml is untouched. When I hit the controller I get following error: Cannot autowire service "AppBundle\Controller\DefaultController": argument "$bus" of method "__construct()" references class "League\Tactician\CommandBus" but no such service exists. You should maybe alias this class to the existing "tactician.commandbus.default" service.
When I define it in my services.yml like this League\Tactician\CommandBus: '#tactician.commandbus.default' everything seems to work, but this is very uncomfortable to define every service I need in this way. Is it the only way or am I missing somehting?
Thanks in advance!

I'm pretty sure you forgot to register the bundle, that's the only way i could repro the issue. Go to your AppKernel.php and add
new League\Tactician\Bundle\TacticianBundle()
in your $bundles array.
L.E. my bad, not the same error message. What version of the bundle are you using? I've got "^1.1" and worked flawless.

Related

PHPStan doesn't use custom entity repository

I am using PHPStan with its Doctrine extension.
I have a custom entity repository called App\Repository\Doctrine\UserRepository with the #extends doc block:
/**
* #extends \Doctrine\ORM\EntityRepository<\App\Entity\User>
*/
class UserRepository extends EntityRepository implements IUserRepository
{
public function customRepositoryMethod()
{
// ...
}
}
In a controller, this code:
public function getUserMatches(EntityManager $em)
{
$userRepo = $em->getRepository(\App\Entity\User::class);
$userRepo->customRepositoryMethod();
}
...results in this PHPStan error:
Call to an undefined method Doctrine\ORM\EntityRepository<meQ\Entity\User>::customRepositoryMethod().
Thanks to phpstan-doctrine, static analysis knows that $em->getRepository(User::class) returns a EntityRepository<User>.
However, it does not know to consider the custom repository class UserRepository as the implementation of that generic type.
How do I DocBlock the UserRepository class, or otherwise configure PHPStan, so that it interprets UserRepository as the implementation of EntityRepository<User>?
What else I've tried
I've also tried this DocBlock on UserRepository to no avail:
/**
* #implements \Doctrine\ORM\EntityRepository<\App\Entity\User>
*/
PhpStan has no way of knowing EntityManager::getRepository() is going to return your custom method.
Either add a #var annotation right there:
/** #var UserRepository $userRepo */
$userRepo = $em->getRepository(\App\Entity\User::class);
Or better yet, just inject the UserRepository, not the whole EntityManager:
public function getUserMatches(UserRepository $userRepository)
{
$userRepository->customRepositoryMethod();
}
The above would work with PhpStan or any static analysis tool out of the box. (And, injecting the specific repository instead of the Entity Manager is a better practice in any case).
But if not, you can always try installing the Doctrine Extensions for PHPStan, which may help the tool understand the codebase in relationship to Doctrine ORM.
If you are already using the Doctrine Extensions, note that from what I gather in the docs it's only able to extract typing if your mapping configuration is provided via annotations. If you configurate ORM mappings via XML (or YAML, in older versions of Doctrine), then I think the Extensions won't be able to extract the typing data, and the above solutions will be your only way to go.

How can I correctly set routes of a new Bundle in an existing Symfony project?

I am working on a Symfony project, where the other developers are not really giving project-specific information, so this work is one of the worst project experience for me in the last five years. I am to create two Symfony bundles, an OrderBundle and an ErpBundle, to create some entities in the OrderBundle along with a service and a controller into ErpBundle.
The entities are normal Doctrine entities, I do not think they are important from this question's point of view. The HomeController is in the folder of
mainfolder/vendor/Myproject/myfolder/src/Myproject/App/ErpBundle/Controller/Admin/HomeController.php and it is like this:
<?php
namespace Myproject\App\ErpBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class HomeController extends AdminController
{
/**
* #Route("/home", defaults={
* "_format": "html"
* })
*/
public function indexAction()
{
//some code
}
/**
* #Route( "/home/menu",
* defaults={"_format": "html"})
*/
public function indexMenuAction()
{
//some code
}
}
Its routing.yml contains this
myproject_app_erp.myproject_admin.controller:
resource: erp
type: myproject_admin
and its sevice.yml contains this
services:
# erp.example:
# class: MyprojectAppErpBundle\Example
# arguments: ["#service_id", "plain_value", "%parameter%"]
parameters:
myproject_app_erp.routing_controllers:
home: 'MyProject\App\ErpBundle\Controller\Admin\HomeController'
And, inside mainfolder/app/config/routing.yml I have this section:
myproject_app_erp:
resource: '#MyprojectAppErpBundle/Resources/config/routing.yml'
In theory this should run the HomeController I need, which, in turn would work with the service I described, which will do something with the entities, but instead of that I get the following error:
The parameter "myproject_app_erp.routing_controllers" must be defined
in erp (which is being imported from
"/var/www/mainfolder/vendor/myproject/sing/src/Myproject/App/ErpBundle/Resources/config/routing.yml").
I have tried to copy the parameters section from the service.yml into the routing.yml to have that section there, which was missed by the error message, but the error message remained. I have been trying to solve this since yesterday with a lot of approaches and I have the impression that I have more difficulties in setting up the working environment than with writing the code. I have read about service creation at the Symfony docs, this is why I have been able to reach as far as I reached, but I do not know how to solve this problem. I think I need to check how autoload works, since it seems that /home routes are controlled there, but I do not know whether I am right and how to reach that. My question is: what should I check, where and how to be able to solve this problem.
EDIT:
I have managed to avoid the error described above by implementing DependencyInjection, but creating a folder with the name of DependencyInjection into the ErpBundle and implementing the following two classes:
Configuration.php
<?php
namespace Myproject\App\ErpBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {#link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/
class Configuration implements ConfigurationInterface
{
/**
* {#inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('myproject_app_erp');
return $treeBuilder;
}
}
MyprojectAppErpExtension.php
<?php
namespace Myproject\App\ErpBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {#link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class MyprojectAppErpExtension extends Extension
{
/**
* {#inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
While the page loads now, it still uses another bundle's HomeController than the one inside ErpBundle.
It turns out that there is a custom routing-specific logic in the project and I had to do some database changes, following a project-specific convention previously unkown to me. The details are so specific, that I cannot share them here without violating the business secrets related to the project, so I know what the answer is, but cannot share this with the community.

Symfony upgrade 3.3 to 3.4 service not found

Trying to upgrade a project from Symfony 3.3 to 3.4. I've done composer update symfony/symfony --with-depdencies and added public: false to my services.yml file.
Now when I run my PHPUnit tests, I get this error:
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException : The service "templating.loader.cache" has a dependency on a non-existent service "templating.loader.wrapped".
Any ideas why this happens? I can't find any Google results or any Symfony documentation references for this at all...
Problem was found to be caused by overriding the definition of templating.loader.cache to public in a compiler pass class to allow access during functional tests.
Based off code here: https://github.com/symfony/symfony-docs/issues/8097
tl;dr do not do this:
final class TestCompilerPass implements CompilerPassInterface
{
/** {#inheritdoc} */
public function process(ContainerBuilder $container)
{
foreach ($container->getDefinitions() as $id => $definition) {
$definition->setPublic(true);
}
}
}
Instead limit the services you make public to the ones you actually require.
Unless you prepared your code for private services you shouldn't use the public: false tag. That is used to mark services as private. Probably somewhere in your code you have something like $var = $container->get('example'); which calls a public service. You can read more here.

Laravel 4 workbench class not found

I'm trying to develop a package in laravel 4 - my first attempt at a package.
I found a couple of tutorials which I've tried to follow:
http://jasonlewis.me/article/laravel-4-develop-packages-using-the-workbench
and
http://culttt.com/2013/06/24/creating-a-laravel-4-package/
and of course in the official documentation.
I've followed the basic structure to create the framework. However on loading the app I get a class not found error. This relates directly to the serviceprovider I have placed in the app.php file.
here's my entry in the providers array:
'Longestdrive\Calendar\CalendarServiceProvider'
My folder structure is:
laravel/workbench/longestdrive/calendar/src/Longestdrive/Calendar
My service provider has the following entries:
<?php namespace Longestdrive\Calendar;
use Illuminate\Support\ServiceProvider;
class CalendarServiceProvider extends ServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
$this->package('longestdrive/calendar');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array();
}
}
I've double checked to spelling and ran a composer dump-autoload both from the root of the project and the root of the package.
I've run out of ideas for solving the class not found any ideas where I've gone wrong?
The line producing the error is this one:
C:\wamp\www\googleapi\laravel\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRepository.php
Any help appreciated
Thanks
Update:
I ran a composer update as suggested in the workbench/package folder with a response nothing to update. I then ran composer at the root of the project and an error was produced:
[RuntimeException]
Error Output: PHP Fatal error: Class 'Longestdrive\Calendar\CalendarServiceProvider' not found
in C:\wamp\www\googleapi\laravel\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRe
pository.php on line 123
I probably posted the wrong error line earlier. The full exception response is:
Class 'Longestdrive\Calendar\CalendarServiceProvider' not found
THe error extract:
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #return \Illuminate\Support\ServiceProvider
*/
public function createProvider(Application $app, $provider)
{
return new $provider($app);
}
which I assume relates to the service provider loader not finding the CalendarServiceProvider?
I found that running composer install from within the workbench/[vendor]/[package] folder solved the problem.
I encountered the same error, so I went deeper on its flow to knew what happens.
So dissecting a little bit basically, in the bootstrap phase, when bootstrap/autoload.php is loaded it runs at the end:
if (is_dir($workbench = __DIR__.'/../workbench'))
{
Illuminate\Workbench\Starter::start($workbench);
}
This requires EVERY workbench/vendor/package/**/**/**/autoload.php he found (by using Symfony Finder Component)
$finder->in($path)->files()->name('autoload.php')->depth('<= 3');
That's important because it's expecting to find workbench/vendor/package/vendor/autoload.php.
Successively in bootstrap/start.php it gets the 'providers' defined in config/app.php and try to load each of them:
$providers = $config['providers'];
$app->getProviderRepository()->load($app, $providers);
and then in ProviderRepository.php
foreach ($providers as $provider)
{
$instance = $this->createProvider($app, $provider);
so we'll end up with:
public function createProvider(Application $app, $provider)
{
return new $provider($app);
where it tried to create an instance of a class isn't really autoloaded. And so that's why the exception thrown!
In conclusion...
As #Ray said, by removing his Service from 'providers' => array( no error is thrown cause return new $myServiceDeclaredInProviderArray($app); never fires for that service.
As #Andrew Holt said
I found that running composer install from within the workbench/[vendor]/[package] folder solved the problem.
He's absolutely right because this create the autoload vendor dir and files, and everything works as we expect it to because it finds the autoload files:
$finder->in($path)->files()->name('autoload.php')->depth('<= 3');
Me
php artisan dump-autoload works as well if you remove the service from the providers array
In addition to #ilpaijin's and #Andrew Holt's answer, there sometimes comes the need (when there's a new version of Laravel) to run composer update within the workbench/vendor/package folder.
Also, as noted here, the composer.json within the package must require the same version of illuminate/support as the one required of laravel/framework in the project root's composer.json.
Thanks to #biscii note that one should use:
"illuminate/support": "4.1.x"
instead of
"illuminate/support": "4.x"

symfony2 routing with annotations not working

I just downloaded symfony2 and am beginning to play with routing via annotations. I have my app/config/routing.yml set in the bundle I created to use annotations, and have deleted the Acme bundle and all routing references to it. That said, I've tried creating a couple different route annotations in my controller like #Route("/") and #Route("/hello/{name}") but I'm always greeted with a 404 error (using the dev environment). If I add the route in routing.yml it works just fine even though the routing is configured to use annotations. For whatever reason, my annotations are seemingly being ignored.
Here is my app/config/routing.yml:
DanDefaultBundle:
resource: "#DanDefaultBundle/Controller/"
type: annotation
prefix: /
And here is my controller method:
/**
* #Route("/")
* #Template()
*/
public function indexAction()
{
return array('name' => 123);
}
I've included the Sensio\Bundle\FrameworkExtraBundle\Configuration\Route namespace - everything as far as I can tell is correct with what I've seen in the documentation. What am I overlooking that's causing symfony2 to seemingly ignore my routing annotations? Again, if I add the routes to the routing yaml everything works so my bundle is working - but annotations seem to be ignored.
Thanks!
Dan
UPDATE:
It looks like I had to add the routes to routing_dev.yml in addition to routing.yml since I was operating in the dev environment. I suppose that's so you have have different routes in-between development and production? I suppose special care will have to be taken to make sure those routes stay in sync?
You accidentally removed the inclusion of routing.yml from routing_dev.yml.
if you use Route Prefix in your routing.yml
you must declare about your prefix above your class declaration like that :
/**
* #Route("/")
*/
class PostController extends Controller
{
/**
* #Route("/")
* #Template()
*/
public function indexAction()
{
}
/**
* #Route("{id}")
* #Template()
*/
public function showAction($id)
{
}
}
Like into Sensio FrameworkExtra Bundle Documentation

Categories