In Symfony2, the command for clearing cache ...
php app/console cache:clear --env=prod
removes completely the app/cache/prod folder. I'd like to preserve the content of http_cache. Is there any way to tell Symfony2 to store the http_cache in other location not affected when do a cache:clear?
For example, there is a simple configuration in config.yml to move sessions out of cache folder, in order to not clear all user sessions on every deployment.
framework:
[...]
session:
save_path: %kernel.root_dir%/var/sessions
Is there some similar way to do this with http_cache folder?
In AppCache.php you can use createStore method.
require_once __DIR__.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
class AppCache extends HttpCache
{
protected function createStore()
{
// Use custom logic to build the store
}
}
Default content of that function looks like that:
protected function createStore()
{
return new Store($this->cacheDir ?: $this->kernel->getCacheDir().'/http_cache');
}
Related
With Symfony, when config or twig files are modified, the cache must be cleared and a warmup must be performed to take into account the new values.
My problem is when users are working on the website and I would like to update a file which needs a Symfony warmup command : the command fails if a user is consulting the cache at the same times by browsing the website. Then the cache is corrupted and I need to run again the clear cache and the warmup command when users are angry because the website is not working and hit the F5 button again and again making this process endless...
To avoid this, I am always planning a maintenance and block website accessibility during the cache warmup.
But, it is a complex task to simply fix a typo, isn't it?
Is there a way to clear and warmup single file? Or any idea to handle this process correctly?
Works for me, might work for you.
I usually have two versions of my app placed side by side. Only one is connected to web server. If I have to make any changes I update inactive version, clear cache, warmup cache, etc. Then I switch active version in web server.
That way you have as much time as you want for maintenance and switch is unnoticeable for your users.
You can also configure web server to allow inactive version to be available in some internal channel. That way, after you done what you wanted to change you can peek if everything works as expected(or let testers do their work) before you go public.
At first you have to register a EventListener:
# /config/services.yaml
parameters:
lockFilePath: "%kernel.root_dir%/../web/.lock"
services:
maintenance_listener:
class: App\EventListener\MaintenanceListener
arguments:
- "%lockFilePath%"
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Then the EventListener itself:
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class MaintenanceListener
{
private $lockFilePath;
public function __construct($lockFilePath)
{
$this->lockFilePath = $lockFilePath;
}
public function onKernelRequest(GetResponseEvent $event)
{
if ( ! file_exists($this->lockFilePath)) {
return;
}
$event->setResponse(
new Response(
'site is in maintenance mode',
Response::HTTP_SERVICE_UNAVAILABLE
)
);
$event->stopPropagation();
}
}
So if you now create a .lock file in /web then your site is in maintenance mode.
If you want to display a special template, you can inject #templating into the EventListener.
I'm currently writing a custom route loader in Symfony 2 that will generate routes based on some configuration options defined in the main config file. The problem is that Symfony caches routes generated by custom routes loaders. Is there a way for me to update the cache when that config file changes?
I defined a configuration like this in app/config/config.yml
admin:
entities:
- BlogBundle\Entity\Post
- BlogBundle\Entity\Comment
My route loader read the config file and generates some routes based on the entities. Now the problem is that once those routes are generated and cached by Symfony I can't change them unless I manually call php app/console cache:clear. What I mean is if I add an entity to the config:
admin:
entities:
- BlogBundle\Entity\Post
- BlogBundle\Entity\Comment
- TrainingBundle\Entity\Training
I will have to manually clear the cache again with php app/console cache:clear in order to create and cache the new routes. I want the routes cache to be invalidated if I change the config, so that a new request to the server will force the regeneration of the routes.
Option 1
If your custom loader class can gain access to the kernel or the container (via DI), you could call the console cache clear command from that class.
E.g.
namespace AppBundle\MyLoader;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpFoundation\Response;
class MyLoader
{
private $kernel;
public function __construct($kernel)
{
$this->kernel = $kernel;
}
public function myFunction()
{
$application = new Application($this->kernel);
$application->setAutoExit(false);
$input = new ArrayInput(array(
'command' => 'cache:clear',
'--env' => 'prod',
));
// You can use NullOutput() if you don't need the output
$output = new BufferedOutput();
$application->run($input, $output);
// return the output, don't use if you used NullOutput()
$content = $output->fetch();
// return new Response(""), if you used NullOutput()
return new Response($content);
}
}
Ref: Call a Command from a Controller
Disclaimer before someone points it out; Injection the kernel/conatiner is not considered "best pratice", but can be a solution.
Option 2
You could also write you own console command that extends Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand that just calls the clear cache command.
Ref ; Call Command from Another
Option 3
This answer also gives you another option
I am trying to learn the Symfony framework and struggling with it. The instructions are not very helpful or assume I know a lot more than I know. I am just trying to create a single web page with proper route and controller. I have been googling to find answers and made some progress but no luck yet. Right now I just have the standard install of Symfony with just default bundles etc. I created a project called "gtest3" and chose PHP for it...
I am not sure where I put the new route in (what file) or maybe it needs to be put in more than one file?
I found the "routing.yml" file which seems that is where I need to put it...
here is what is in there right now:
gtest3:
resource: "#gtest3Bundle/Resources/config/routing.php"
prefix: /
app:
resource: "#AppBundle/Controller/"
type: annotation
I am guessing I need to add something to this and put the location/filename of the controller? I have tried doing this a few ways and just get errors.
There is also the "routing.php" file that is referenced in the above code. I am not sure if this is the "controller" or if it is an additional piece of the "route". Here is the code from that file:
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
$collection = new RouteCollection();
$collection->add('gtest3_homepage', new Route('/hello/{name}', array(
'_controller' => 'gtest3Bundle:Default:index',
)));
return $collection;
I am not sure what if anything I would add here.
Finally - there is the "DefaultConroller.php" file I found as well which may also be the controller. I dont think I need to include the code of that file here.
So - all I am trying to do is create a route of maybe "/gman" and then have the controller just echo something on the page. Super basic stuff. And I cannot figure out how to get this going.
Can anyone help with this? Thanks so much...
You can define your routes in three ways, either by using yml files, xml files, or by using a php file. This is documented behaviour.
You are from the looks of your routing.yml trying to set up a php version. I would not recommend it, and instead use configuration over coding the routing.
The annotation example would look like:
Adding a controller:
namespace Gtest3Bundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class Gtest3Bundle extends Controller
{
/**
* #Route("/hello/{name}")
* #Template()
*/
public function indexAction($name)
{
return array('name' => $name);
}
}
And add in your app/config/routing.yml:
gtest3:
resource: "#Gtest3Rights/Controller/"
type: annotation
prefix: /what-ever-you-want
You can check what kind of routes you have defined by using:
./app/console router:debug
If it doesn't appear hear, you have something misconfigured.
Please be advised that your bundle names breaks the convention of how bundles should be named in the symfony2 context.
It is advised to use NamespaceProjectBundle. This also documented. If you are stuck, try generating a bundle via the ./app/console generate:bundle. This way you can create a whole symfony2 structure which should show the default page hello/foo page just fine.
If it doesn't seem to run at all, make sure you have registered your bundle at the in the app/AppKernel.php file in the registerBundles() method.
To configure routes you can use yml, php or xml file. You can specify it in app/config/config.yml
framework:
router:
resource: "%kernel.root_dir%/config/routing.yml"
It's where you can check which file is used now.
There are some manners to store the routes.
app:
resource: "#AppBundle/Controller/"
type: annotation
This is how you use routes by writing annotations above your actions (eg indexAction) inside your controller class. Read more.
Another common approach is to build one or more .yml files inside each Bundle.
in app/config/routing.yml you should write this:
app:
resource: "#AppBundle/Resources/config/routing.yml"
prefix: /
Then you need to create the file (and directories if necessary) src/AppBundle/Resources/config/routing.yml and add the following content:
app_homepage:
path: /
defaults: { _controller: AppBundle:Default:index }
It will then try to find the DefaultController and fires the indexAction in the AppBundle (src/AppBundle/Controller/DefaultController.php).
To debug your routes simply type in your console from your projects directory:
app/console router:debug
I am working on a new website being built in SilverStripe. Currently I am having a ton of trouble trying to get the system to let me change the URL alias (or create a second one) for the Security controller's login (and eventually logout) function.
I have tried playing around with the routes.yml file and I tried creating the paths in my own UserController and loading directly from the Security controller with "return Security::login()". But that gives me errors about the use of the static functions.
Unfortunately I don't come from a ton of object oriented experience and this is the first CMS I have used that actually uses a bunch of true object orientation. The current version of SilverStripe we are using is 3.0 (but we will be upgrading to 3.1.1 in a few days).
Does anyone know much about the routing in SilverStripe?
as you stated correctly, SilverStripe has routes, and they can be defined in a yaml config file.
if you take a look at the existing routes.yml in the framework you can see how the default security route is defined:
https://github.com/silverstripe/silverstripe-framework/blob/fd6a1619cb7696d0f7e3ab344bc5ac7d9f6cfe77/_config/routes.yml#L17
if you just want to replace the Secuirty in Secuirty/login, its as easy as just creating your own routes.ymlin mysite/_config/ with the following content:
---
Name: myroutesorsomeotherrandomname
Before: '*'
After:
- '#rootroutes'
- '#coreroutes'
- '#modelascontrollerroutes'
- '#adminroutes'
---
Director:
rules:
'foobar//$Action/$ID/$OtherID': 'Security'
NOTE: make sure you ran a ?flush=1 to ensure the yml file is loaded (they get cached)
also make sure you use spaces in the yml file, if you use tabs you are going to have a bad time
if you however wish to also replace /login and /logout this is no longer a thing for routing.
login and logout are actions (php functions that are listed in Security::$allowed_actions and thus available as URL) on the on Security.
but its still rather easy, just subclass Security and create the actions you want:
<?php
class MySuperSecurity extends Security {
private static $allowed_actions = array(
'showMeTheLoginForm',
'alternative_login_action_with_dashes',
'doTheLogout',
);
function showMeTheLoginForm() {
// can be visited via http://website.com/foobar/showMeTheLoginForm
return $this->login();
}
function alternative_login_action_with_dashes() {
// can be visited via http://website.com/foobar/alternative-login-action-with-dashes
return $this->login();
}
function doTheLogout($redirect = true) {
// can be visited via http://website.com/foobar/doTheLogout
return $this->logout($redirect);
}
}
and make the route point to your new class instead of Security inside the routes.yml:
'foobar//$Action/$ID/$OtherID': 'MySuperSecurity'
NOTE: again, make sure you did a ?flush=1, both the private static $allowed_actions as well as the yml config file are cached by silverstripe.
NOTE: both solutions suggested in this post will create an additional route to login and does not replace the existing one, so the old Security/login will still be available
I don't know nothing about SilverStripe excepting that is a CMS, but i think SilverStripe must provide a way to aliases Url. Also an alternative is create Alias in virtual host definition if you're using apache or in .htaccess file. Refer to apache doc to further details. If you post a skeleton of your .htaccess file or VirtualHost definition i could help you.
The question is as follows:
How can I get the server path to the web directory in Symfony2 from inside the controller (or from anywhere else for that reason)
What I've already found (also, by searching here):
This is advised in the cookbook article on Doctrine file handling
$path = __DIR__ . '/../../../../web';
Found by searching around, only usable from inside the controller (or service with kernel injected):
$path = $this->get('kernel')->getRootDir() . '/../web';
So, is there absolutely no way to get at least that 'web' part of the path? What if I, for example, decided to rename it or move or something?
Everything was easy in the first symfony, when I could get like everything I needed from anywhere in the code by calling the static sfConfig::get() method..
There's actually no direct way to get path to webdir in Symfony2 as the framework is completely independent of the webdir.
You can use getRootDir() on instance of kernel class, just as you write. If you consider renaming /web dir in future, you should make it configurable. For example AsseticBundle has such an option in its DI configuration (see here and here).
To access the root directory from outside the controller you can simply inject %kernel.root_dir% as an argument in your services configuration.
service_name:
class: Namespace\Bundle\etc
arguments: ['%kernel.root_dir%']
Then you can get the web root in the class constructor:
public function __construct($rootDir)
{
$this->webRoot = realpath($rootDir . '/../web');
}
You also can get it from any ContainerAware (f.i. Controller) class from the request service:
If you are using apache as a webserver (I suppose for other
webservers the solution would be similar) and are using
virtualhosting (your urls look like this - localhost/app.php then you can use:
$container->get('request')->server->get('DOCUMENT_ROOT');
// in controller:
$this->getRequest()->server->get('DOCUMENT_ROOT');
Else (your urls look like this - localhost/path/to/Symfony/web/app.php:
$container->get('request')->getBasePath();
// in controller:
$this->getRequest()->getBasePath();
You are on Symfony, think "Dependency Injection" ^^
In all my SF project, I do in parameters.yml:
web_dir: "%kernel.root_dir%/../web"
So I can safely use this parameter within controller:
$this->getParameter('web_dir');
My solution is to add this code to the app.php
define('WEB_DIRECTORY', __DIR__);
The problem is that in command line code that uses the constant will break. You can also add the constant to app/console file and the other environment front controllers
Another solution may be add an static method at AppKernel that returns DIR.'/../web/'
So you can access everywhere
UPDATE: Since 2.8 this no longer works because assetic is no longer included by default. Although if you're using assetic this will work.
You can use the variable %assetic.write_to%.
$this->getParameter('assetic.write_to');
Since your assets depend on this variable to be dumped to your web directory, it's safe to assume and use to locate your web folder.
http://symfony.com/doc/current/reference/configuration/assetic.html
For Symfony3
In your controller try
$request->server->get('DOCUMENT_ROOT').$request->getBasePath()
$host = $request->server->get('HTTP_HOST');
$base = (!empty($request->server->get('BASE'))) ? $request->server->get('BASE') : '';
$getBaseUrl = $host.$base;
Since Symfony 3.3,
You can use %kernel.project_dir%/web/ instead of %kernel.root_dir%/../web/