Force configuration reload in Symfony2 - symfony

I have a script which makes changes to the Symfony2 configuration and needs to be made aware of the new configuration before proceeding (specifically adding dbal connections). Is there a way to force the reload of the configuration during script execution?

Update: You can't reload the configuration, but you can set the parameters on-the-fly, see second "Update" paragraph
It's not really possible in Symfony2 to do that.
In production mode, everything (even the configuration) is cached, so you have to clear the cache with
app/console cache:clear --env=prod --no-debug
(maybe followed by a app/console cache:warmup --env=prod --no-debug)
to reload the configuration. In development mode you could experiment with shutdown() followed by a boot() from Symfony\Component\HttpKernel\Kernel or maybe loadClassCache - but all of this is not really that what you want.
What exactly changes are made to the configuration files? Maybe you should use different files for different environments or consider any other method to get those changes (via a simple Webservice or even a static file read from within a Controller).
Update:
I figured out that you can set your container configuration parameter on-the-fly via
$container->setParameter('parameter', value);
Have a look at the Symfony2 documentation.

My answer probably arrives very late but could be useful to someone else.
Symfony cache for "prod" environment is stored in "app/cache/prod/" folder and contains many things (Twig templates translated in PHP in "twig/" subfolder, annotations in "annotations/" subfolder, and... configuration parameters, app*ProjectContainer.php files, among many other things).
So what you can do is: when your configuration script changes parameters.yml, it can also delete appProdProjectContainer.php. The next user to hit your Symfony app will face a little longer response time, but the new configuration parameter will be taken into account and cached.

Here is the partial solution, besides I used it in Symfony 3.2, but nevertheless this code is used to reload bundle configuration on the fly.
Firstly, you should inject container instance inside the service / controller where you want to use bundle instance which was reinitialized with other config:
/**
* Service constructor.
*
* #param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$container = ReinitializedBundleExtension::updateContainerWithProdConfiguration($container);
}
Secondly, you should add a method to ReinitializedBundleExtension class which will update the container with reinitialized bundle instance and dependencies:
/**
* Updates container with bundle services resolved with production configuration.
*
* #param ContainerInterface $oldContainer
*
* #return ContainerInterface $container
*/
public static function updateContainerWithProdConfiguration(ContainerInterface $oldContainer)
{
$containerBuilder = new ContainerBuilder();
// Copy external services used in the bundle.
$logger = $oldContainer->get('logger');
$containerBuilder->set('logger', $logger);
// Load the production config files.
$bundleResourcesPath = $oldContainer->get('kernel')->locateResource('#ReinitializedBundle/Resources/');
$fileLocator = new FileLocator($bundleResourcesPath . '/config');
$loader = new Loader\YamlFileLoader($containerBuilder, $fileLocator);
$loader->setResolver(new LoaderResolver([$loader]));
$loader->load($bundleResourcesPath . 'config/production/services.yml');
// Resolving bundle services with prduction config.
$containerBuilder->compile();
$containerBuilder->resolveServices($containerBuilder->getDefinitions());
// Merge resolved prod-configured services with old container.
$serviceIds = $containerBuilder->getServiceIds();
foreach ($serviceIds as $serviceId) {
// Services which are not related to the bundle.
if (strpos($serviceId, 'reinitialized_bundle_config_prefix') === false) {
continue;
}
$oldContainer->set($serviceId, $containerBuilder->get($serviceId));
}
return $oldContainer;
}
PS:
1. All the ReinitializedBundle params and services are marked with 'reinitialized_bundle_config_prefix' prefix, so it's easy to recognize them in container, i.e:
reinitialized_bundle_config_prefix.service1
reinitialized_bundle_config_prefix.param1
This is a solution for Yaml configs, so YamlFileLoader was used.
ReinitializedBundle config filestructure:
.ReinitializedBundle
└── Resources
└── config
├── production
| ├─── services.yml
| └─── other stuff
└── staging
├─── services.yml
└─── other stuff

Related

bundle's service (autowire) not available in controller's method

I'd like to use https://github.com/tedious/TedivmStashBundle bundle in my symfony 4 project. Added by composer, configured in /config/stash.yaml file and according to the profiler bar, it's working basically.
Now, I want to use to caching values in my controller. I've try to add the service stash by its name to the method's parameter, using the same name as the example says:
$pool = $this->container->get('stash');
but the framework did not find the service. It can't be added like the example explained neither.
How can I use this bundle as a service (autowired) in my symfony 4 app?
UPDATE
services.yaml:
stash.default_cache:
class: Tedivm\StashBundle\Service\CacheService
public: true
arguments:
$name: 'stash'
Tedivm\StashBundle\Service\CacheService: '#stash.default_cache'
Controller:
public function something(Request $request, CacheService $service, ...
It's looks like working now :)
Thanx for the suggestion (and the correct solution later) to #Cerad
Here is an example of how to approach this sort of problem when dealing with bundles that are not quite ready for autowire.
Start by installing a test project:
symfony new --full stash --version=lts
composer require tedivm/stash-bundle
Note that the bundle does not directly support Symfony 5 hence the lts. Note also that the bundles does not support Flex so you have to add your own config/packages/stash.yaml file per the bundle's readme file.
# config/packages/stash.yaml
stash:
drivers: [ FileSystem ]
FileSystem: ~
At this point we can determine which service we need to inject:
bin/console debug:container stash
Information for Service "stash.default_cache"
=============================================
Class CacheService
---------------- -----------------------------------------
Option Value
---------------- -----------------------------------------
Service ID stash.default_cache
Class Tedivm\StashBundle\Service\CacheService
Most of the time you would like to use an interface for injection but a peek at the source code reveals that the bundle does not use interfaces. As a side note, calling a third party service 'stash' is not a good idea. It really should have been 'tedivm.stash' but I digress.
We can now create an alias and then typehint against it:
# config/services.yaml
Tedivm\StashBundle\Service\CacheService : '#stash' # alias for typehinting
# Controller class
public function index(CacheService $cacheService)
{
return new Response('Cache ' . get_class($cacheService));
}
And that should do it.

PhpStorm Doesn't Recognize Doctrine Entity Classes

PhpStorm doesn't seem to recognize any of my Doctrine entity classes or their methods.
$comment = $em->getRepository('MyBundle:Comment')->findOneBy(array('id' => $id));
$comment->getId();
/* PHPSTORM THROWS WARNING: Method getId() not found in subject class */
The error goes away, only when I explicitly comment it - which really clutters my controller.
/* #var \MyBundle\Entity\Comment $comment */
$comment = $em->getRepository('MyBundle:Comment')->findOneBy(array('id' => $id));
Is there a way to document this for PhpStorm in my Entity Class?
I'm using the Symfony2 plugin with PhpStorm 8. Thanks!
I had this issue. Magically solved by clearing the Doctrine metadata:
php app/console doctrine:cache:clear-metadata
EDIT: In GitHub reposiory of the symfony plugin there is a brief description on what to do when this issue happens:
https://github.com/Haehnchen/idea-php-symfony2-plugin
Autocomplete (or something else) is not working! Help!
[...]
Many features require the
app/cache/dev/appDevDebugProjectContainer.xml file to exist. It is
generated when you boot your app in dev environment (open /app_dev.php
in a browser or php app/console).
Since my server is remote, manually synchronizing the file app/cache/dev/appDevDebugProjectContainer.xml solved my problem.
When I was working on a local server, instead, the command I wrote above helped me to make autocomplete work again.
I have the same problem with the Symfony2 Plugin, this is maybe not a nice solution but it works
/** #var EntityManager $em */
$em = $this->doctrine->getManager();
your issue should be fixed, now. there was a problem on multiple getRepository implementations of proxy classes in cache folder. just update to >= 0.11.81
Now, I prefer declaring repositories as services so you don't have those typehint problems:
services:
MyBundle\Entity\CommentRepository:
class: MyBundle\Entity\CommentRepository
public: true
factory: ['#doctrine', getRepository]
arguments:
- MyBundle\Entity\Comment
Then in your controller :
use MyBundle\Entity\CommentRepository;
$comment = $this->get(CommentRepository::class)->findOneBy(['id' => $id]);
Try to invalidate caches of PhpStorm. Go to file->Invalidate caches

Symfony2 updated entity works on dev but not on prod

I recently had to add new 'field' to Product in my sonata application so i added it in entity devinition ...
/**
* #var integer $deliveryTime
*/
protected $deliveryTime;
/**
* Get deliveryTime
*
* #return integer $deliveryTime
*/
public function getDeliveryTime()
{
return $this->deliveryTime;
}
/**
* #param int $deliveryTime
*/
public function setDeliveryTime($deliveryTime)
{
$this->deliveryTime = $deliveryTime;
}
in ORM
<field name="deliveryTime" column="delivery_time" type="integer" nullable="true" />
in ProductProvider
$formMapper->add('deliveryTime', 'integer')
and in all the views
It works perfectly on my local environment but when i moved it to production it doesn't work.
Funny thing is that if i access dev environment on my production server it shows the delivery time for products but on prod environment it doesn't.
I cleared cache with --env=prod option, even physically deleted cache files from both dev and prod folders but it won't help.
Database is not the issue because it wouldn't work on dev env if the reason was database.
Any ideas what else should i do to make it work on prod env?
(i can switch to dev env without the toolbar but it's not 'nice' approach:)
UPDATE: #moonwave99 yes i did update the database and there's nothing related in app_prod.log
what doesn't work on prod and works on dev:
- showing delivery time for product from the database in product view
- showing/updating delivery time through the admin panel
This was strange - i restarted apache service on production server and now it works.
Try running a few commands,
php app/console doctrine:schema:update --force
php app/console cache:clear
php app/console cache:clear --env=prod --no-debug
if that fails re-push your code
and re run above
Hope that helps
You should to reload APC. Prod environment saves doctrine cache in this system.
If you use PHP + Apache - restart apache
If you use PHP-FPM - restart php-fpm.

Symfony 2 (2.3.x) Annotation Route not working

I'm new on symfony and I'm following this tutorial:
http://it.siciarek.pl/docs/references/howtostart.html
At some point at the end of the installation process (after getting rid of ACME) I've created a new Bundle
php app/console generate:bundle --bundle-name=AgcoukMainBundle --namespace=Agcouk/MainBundle --dir=src --format=annotation --structure --no-interaction
my DefaultController looks like:
namespace Agcouk\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DefaultController extends Controller
{
/**
* #Route("/", name="home")
* #Template()
*/
public function indexAction()
{
return array();
}
}
and my routing.yml (app/config/routing.yml)
agcouk_main:
resource: "#AgcoukMainBundle/Controller/"
type: annotation
prefix: /
Now, trying to access the page sf2/ (sf2/config.php works!) I get a 404 Error.
I've even debugged the routes via console (php app/console router:debug home) and everything looks fine to me
[router] Route "home"
Name home
Path /
Host ANY
Scheme ANY
Method ANY
Class Symfony\Component\Routing\Route
Defaults _controller: Agcouk\MainBundle\Controller\DefaultController::indexAction
Requirements NO CUSTOM
Options compiler_class: Symfony\Component\Routing\RouteCompiler
Path-Regex #^/$#s
(I've tried even to specify the Controller file name in the routing.yml and nothing changes, even the debug gives the same result).
Any clue?
Thanks
First of all you should use Symfony's Official Documentation... www.symfony.com
This tutorial you are following are even writing the framework's name wrong: "Symphony", so maybe is out of date or something.
And have you tried to clear your cache? php app/console cache:clear --env=dev
Inspired by this post:
symfony2 - how to switch from "dev" to "prod"?
I've finally solved the issue. I've manually deleted the files in app/cache/dev and app/cache/prod and then I've changed the owner of the prod cache folder
sudo chown www-data app/cache/prod
now, pointing at my virtual host (sf2) the page is loaded with no 404 Error.

Unit testing a symfony service class with phpunit

I have a basic class GenericHelper.php in directory Foo/BarBundle/Helper
I registered it as a service in Foo/BarBundle/Resources/config/services.yml:
parameters:
generic_helper.class: Foo\BarBundle\Helper\GenericHelper
services:
generic_helper:
class: %generic_helper.class%
and I'm able to access it in a command by doing the following:
$helper = $this->getContainer()->get('generic_helper');
Now, I'd like to unit test that class with PHPUnit; I have the following code (similar to http://symfony.com/doc/2.0/book/testing.html#unit-tests):
namespace Foo\BarBundle\Tests\Helper;
use Foo\BarBundle\Helper\GenericHelper;
class GenericHelperTest extends \PHPUnit_Framework_TestCase {
public function testSomeMethod() {
$helper = new GenericHelper(); //line 10
$this->assertEquals($helper->someMethod(), SOME_RESULT);
}
}
Running PHPUnit results in the following error:
PHP Fatal error: Class 'Foo\BarBundle\Helper\GenericHelper' not found in /DIR/src/Foo/BarBundle/Tests/Helper/GenericHelperTest.php on line 10
Grepping for 'GenericHelper' only yields a few results:
the Class itself and the Test class
the services.yml file
appDevDebugProjectContainer files in app/cache/dev/, which have all the service getters
Question(s):
Does Symfony prevent PHPUnit from directly constructing a service class?
Is there a way to do this without creating a Symfony Container then accessing the service (as done here: Access Symfony 2 container via Unit test?)? I mean, it's still just a basic class...
Running phpunit with the -c flag pointing to the directory containing the phpunit.xml.dist file solved the issue. Doing this includes bootstrap.php.cache and therefore the autoloading stuff necessary.

Resources