Today I have identified a bottleneck in my Symfony application. The problem is that Symfony calls Doctrine\Common\Annotations\CachedReader::getMethodAnnotations() over 4000 times (for every request, in production mode).
I looked at the callstack and these calls are a result of Symfony\Component\Routing\Loader\YamlFileLoader::load() which is called by Symfony\Bundle\FrameworkBundle\Routing::getRouteCollection(). This seems to be the core issue - it seems the RouteCollection is not cached.
After some research I found this comment by #stof saying that RouteCollection should not be used at runtime.
The runtime usage of RouteCollection is done by the CsrfRouteBundle. To be precise it's used here and here. Does this mean that the approach used by this bundle is wrong? In that case what solution do you use for CSRF in symfony?
Related
I am working in a controller, the code that I change must stay here. The routes are defined as annotations in the controller.
So, maybe it is not the cause, but whenever I make a change to my code and refresh my page, the first refresh is very slow (the project is huge, many controllers).
After a first refresh, the next ones are quick. So I guess symfony detects the controller has changed and rebuilds the router cache.
This is painful.
How can I temporarily disable re-scanning the whole project for routes ?
Significant delays in dev environment are caused by container re-building. It is actually very good decision from Symfony developers because it allows you to focus on development itself and don't waste time trying to hunt mysterious bugs that will be actually caused by hidden incompatibilities between your code and container contents.
Simplest way to avoid automatic container re-building is to switch to prod environment where Symfony expects you to care about container by yourself. However in this case you will also lose a lot of other convenient tools that are provided by Symfony into dev environment.
There is also slightly harder alternative. Take a look at Kernel::initializeContainer() method, it is responsible for container initialization. As you can see from the code - Symfony checks if container is fresh. It is done by loading .meta files that resides in container and checking if all files listed in them are same as they was at a time of container building. Since this method is quite internal - it is not open for simple modifications but you can copy / paste it into your application's container and modify to match your needs. Of course you need to understand that this approach can't be treated as recommended way and unlikely supported by Symfony developers so you have to accept possible consequences, but still - it is possible to implement.
Normally, application is bootstrapped after request being created. But in a test environment it happens before creating request.
That leads to socialiteproviders/manager implicitly creating request here, thinking it already exists. This request doesn't get used, and the other one is created after that.
As a result, I can't forge session data with withSession helper. Since it changes session created for latter request. And SocialiteProviders' provider always gets empty session.
If I disable bootstrapping it here, the first error I get is at this line, since application has not being bootstrapped yet.
Who's at fault? And how to fix it? And can you think of any workarounds meanwhile?
P.S. More details here.
Well, if I had to answer who's at fault, I'd say it's socialiteproviders/manager, since it makes an assumption that request is already created when application is being bootstrapped. And here's the solution the way I see it.
To use it you add
{
"type": "vcs",
"url": "https://github.com/x-yuri/Manager"
}
to repositories parameter of composer.json. And do
$ composer require 'socialiteproviders/manager=dev-testing-boot as 2.2.1'
Do note though, using extra repositories slows composer down.
What I am doing ?
Below is the code to get and set the data in cache
\Cache::put('Categories', $Categories, 60);
\Cache::forget('Categories');
Question
What's the recommended location to get and set the Cache code ? So far I did this in the Controller file.
Take a look at Laravel 5.1 Cache especially Cache Usage part, where you set or get cache depending to you and workflow of your app.
I recommended to use them inside controllers.
Like with most of the questions of Where Do I Put X the answer is it depends. There is absolutely nothing wrong with doing it in your controller if your doing a small application and maybe only caching a few things.
If your writting a really big application or something quite complexted then you could consider doing your caching via a repository see Using Repository Pattern in Laravel 5 for some information about the Repository Pattern. If you wanted you could make use of Laravel 5 Repositories this provides not only a clean and well documented way to implement repositories but also it has specific way of doing caching see Cache Usage.
My Symfony2 application has some performance problems, so I ran a webgrind on it in order to see what was happening. Turns out it was parsing huge amounts of YML files on every request and I can't figure out why. I already have APC caching enabled so I don't know what it could be. Any help with this issue would be much appreciated.
Edit: Here is a screenshot of the webgrind I ran.
From my research, it appears that the APCClassLoader does not cause Symfony2 to cache the YAML files used in Doctrine. It appears to cache the configuration files by default (config.yml, parameters.yml), but the actual ORM YAML files used by Doctrine are not cached unless you specify a cache driver as shown in the documentation linked below:
http://symfony.com/doc/2.3/reference/configuration/doctrine.html#caching-drivers
So, it's possible that the solution above solved the issue if the poster had only configuration YAML and not doctrine YAML. However, if Doctrine YAML is involved, a Doctrine cache driver must be specified.
This also affects people using Annotations as they will be parsed on each page load unless a cache driver is specified (other than the Doctrine default array cache).
Thought I should post because this is a complex issue and the answer above was misleading in my case where Doctrine ORM YAML files were the source of the caching issue.
This post has more details on my specific issue and the resolution:
Why is Symfony2 app spending 70-90% of its time parsing YAML?
Figured out what was going on. I had APC enabled and working, but wasn't using the ApcUniversalClassLoader in my autoload.php. More details here. When they say in the docs "suggestions" for improved performance they really mean "you have to do this or your performance will be terrible."
I have integrated Doctrine 2 with ZF1, using both the Bisna integration and my own custom integration.
The models work fine in unit tests via the shepp.
However when I run the web application, I get an error with the Proxies. The proxy for a model User.php is __GC_User.php and is placed in the correct location. However I get an error when the auto loader tries to load the Proxy class since its looking for \_GC__\User.php.
How can I fix this?
I thought that I would post an answer to help others dealing with Doctrine 2 proxies. My problem was that I was storing an entity into a Zend_Cache instance, and the entity had some Doctrine2 proxies attached.
So when I removed the caching then the issue went away. So the rule of thumb is do not store entities in Cache, just store identifiers