I need to send a parameter to all my views (twig template) with Symfony2.
Each view extend a special view : base.html.twig, so I think I just need to send this parameter to this base view.
But how can I do that?
Here is the way I get this parameter in my php file:
$svn = File('.svn/entries');
$svnrev = $svn[3];
Which represents the number of current revision.
Is there a way to retrieve this variable in a .yml?
You should register a global variable using a twig extension.
The class
// src/Acme/YourBundle/Twig/SvnExtension.php
namespace Acme\YourBundle\Twig;
class SvnExtension extends \Twig_Extension
{
public function getGlobals()
{
// you might need to adapt the file path
$svn = File('.svn/entries');
return array(
'svn_rev' => $svn[3]
);
}
public function getName()
{
return 'svn_extension';
}
}
The service definition
# i.e. app/config/config.yml
services:
acme.twig.svn_extension:
class: Acme\DemoBundle\Twig\SvnExtension
tags:
- { name: twig.extension }
Accessing the variable
Now your variable is accessible in every twig template as usual:
{{ svn_rev }}
Further improvements would include:
getting the filename from a parameter or environment variable (if the svn repo is stored elsewhere)
caching the file using apc(u) / memcache / whatever for performance
add more svn info and turn the variable into an array itself ( svn.rev , svn.state , ... )
...
Related
I have a controller with a supprimer action.
I can add files and delete them from the database.
As I followed the Symfony doc to create an uploader file, I also created in my services.yml this route
parameters:
repertoire_soumissions: '%kernel.project_dir%/public/uploads/LettresSoumissios'
My problem
When I delete my file with my supprimer action, it's fine it deletes it in my database. But not in my folder /public/uploads/LettresSoumissions. I tried to find a way to be able to delete them in my folder too, but couldn't succeed it.
I tried also with a Filesystem() to remove them, but I've must have written it badly.
Here is my action in my controller class
/**
* #Route("admin/soumission/{id}/supprimer", name="supprimer_soumission")
*/
public function supprimerSoumission(Soumission $soumission, ObjectManager $manager){
$lettresoumission= $soumission->getLettreSoumission();
$filesystem = new Filesystem();
$path='%kernel.project_dir%/public/uploads/LettresSoumissios/'.$lettresoumission;
$filesystem->remove($path);
$manager->remove($soumission);
$manager->flush();
$this->addFlash('success','Soumission supprimer !!');
return $this->redirectToRoute('soumission');
}
Could it be due to a mispelling in the path name?
$path='%kernel.project_dir%/public/uploads/LettresSoumissioNs/'.$lettresoumission;
Missing a N letter.
Your problem is this line:
$path='%kernel.project_dir%/public/uploads/LettresSoumissios/'.$lettresoumission;
The parameter above is simply a string with value:
%kernel.project_dir%
You need a way to retrive the value of the parameter.
A clean way would be to inject the parameter value in the controller.
Define your Controller as a service in your service.yaml:
Namespace\NameOfTheController:
arguments:
- '%kernel.project_dir%'
tags: [controller.service_arguments]
Inject the value in the Constructor of your Controller:
private $kernelRoot;
public function __construct(string $kernelRoot)
{
$this->kernelRoot = $kernelRoot;
}
Now change your code-line to:
$path=$this->kernelRoot.'/public/uploads/LettresSoumissios/'.$lettresoumission;
to clarify:
You said:
I also created in my services.yml this route
parameters:
repertoire_soumissions: '%kernel.project_dir%/public/uploads/LettresSoumissios'
This is no service or route declaration, this is just a parameter => value mapping.
I am noobie at ZF3, We have placed zend based admin panel inside codeigniter based main app. like following way
my_app/zend_admin/
|
|
--- config
--- module
--- public
i can access zend module using www.my_app.com/zend_admin/my_zend_controller/my_zend_action.
I want to access www.my_app.com/my_ci_controller/my_ci_action.
Is there any method zend provide as ci provides base_url() so i can fetch my ci controller??
to get base URL you can use serverUrl view helper (like in codeigniter base_url())
$this->serverUrl(); // return http://web.com OR
$this->serverUrl('/uri'); // return http://web.com/uri
I am not sure about your setup but try that...
There are several ways you can get this job done using ZF micro tools.
There are some similar view helpers in the ZF like CodeIgniter has. You can use them for the purpose in the view script and layout template.
Lets start up using module.config.php of your module. You can set up base_path key under view_manager key as follows
'view_manager' => [
'base_path' => 'http://www.yoursite.com/',
]
Now if you use the following view helper
echo $this->basePath();
// Outputs http://www.yoursite.com/
If you use the following one
echo $this->basePath('css/style.css');
// Outputs http://www.yoursite.com/css/style.css
But if you do not use the above configuration
echo $this->basePath('css/style.css');
// Outputs css/style.css
As #tasmaniski said about $this->serverUrl(); you can use that too in the view script. Good thing for this does not need any configuration like $this->basePath()
What if you need this in the controller action of ZF. The easiest way to do it in the controller action is
public function indexAction()
{
$uri = $this->getRequest()->getUri();
$baseUrl = sprintf('%s://%s/', $uri->getScheme(), $uri->getHost());
// Use this $baseUrl for your needs
// Outputs http://www.yoursite.com/
}
Otherwise, you can get it the following way but this works same as $this->basePath()
public function indexAction()
{
// This is for zf2
$renderer = $this->getServiceLocator->get('Zend\View\Renderer\RendererInterface');
// This is for zf3
// Assuming $this->serviceManager is an instance of ServiceManager
$renderer = $this->serviceManager->get('Zend\View\Renderer\RendererInterface');
$baseUrl = $renderer->basePath('/uri');
// Use this $baseUrl for your needs
// Outputs http://www.yoursite.com/uri
}
Moreover, there are two more functions that can be used under different conditions in the controller actions. Those return empty string if rewriting rules used. Those are
$this->getRequest()->getBaseUrl();
$this->getRequest()->getBasePath();
These do not work as you expect I mean as you expect. Must refer to the issue to know why is this!
I'm trying to achieve this
http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html#more-advanced-loaders
I need the bundle routing to automatically activate itself when the bundle is registered
so I created this file into the path
src/Gabriel\AdminPanelBundle\Routing\AdvancedLoader.php
with the content
<?php
//namespace Acme\DemoBundle\Routing;
namespace Gabriel\AdminPanelBundle\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\RouteCollection;
class AdvancedLoader extends Loader
{
public function load($resource, $type = null)
{
$collection = new RouteCollection();
$resource = '#GabrielAdminPanelBundle/Resources/config/import_routing.yml';
$type = 'yaml';
$importedRoutes = $this->import($resource, $type);
$collection->addCollection($importedRoutes);
return $collection;
}
public function supports($resource, $type = null)
{
return $type === 'advanced_extra';
}
}
I copied this configuration
gabriel_admin_panel:
resource: "#GabrielAdminPanelBundle/Controller/"
type: annotation
prefix: /superuser
from
/app/config/routing.yml
and pasted it into my own configuration file
/src/Gabriel/AdminPanelBundle/Resources/config/import_routing.yml
The problem:
Symfony2 completely ignores my AdvancedLoader.php file, I can put any
syntax error in it and the site won't even throw an error, also the
router:debug doesn't show the routes that are defined inside of the
bundle unless I move the configuration back into its original router.yml file.
PS: clearing the cache doesn't change anything
Edit: when I add the service and the resource, this error appears
FileLoaderImportCircularReferenceException: Circular reference
detected in "/app/config/routing_dev.yml"
("/app/config/routing_dev.yml" > "/app/config/routing.yml" > "." >
"#GabrielAdminPanelBundle/Controller/" >
"/app/config/routing_dev.yml").
Looks like you could have missed some steps in the process.
First one: did you define the service?
services:
gabriel.routing_loader:
class: Gabriel\AdminPanelBundle\Routing\AdvancedLoader
tags:
- { name: routing.loader }
Note the tag. As the documentation says:
Notice the tag routing.loader. All services with this tag will be
marked as potential route loaders and added as specialized routers to
the DelegatingLoader.
Second but very important because, as the documentation says, if you didn't add this lines your routing loader wouldn't be called:
# app/config/routing.yml
Gabriel_Extra:
resource: .
type: advanced_extra
The important part here is the type key. Its value should be "advanced_extra" in your case. This is the type which your AdvancedLoader supports and this will make sure its load() method gets called. The resource key is insignificant for the AdvancedLoader, so it is set to ".".
I think it will get loaded now.
I found the following undocumented feature in the documentation chapter Miscellaneous Configuration:
A resource file can be one of many types. PHP, XML, YAML, INI, and
closure resources are all supported by the imports directive.
The class in charge of loading these resources seems to be:
Symfony\Component\DependencyInjection\Loader\ClosureLoader ( APIdoc , Code )
In my understanding according to the documentation it should be possible to import services and/or parameters using a PHP closure inside a configuration file.
non-working example:
# app/config/config.yml
imports:
# closure? something like eval( <multiline-string> ) ?
- { resource: >
function($containerBuilder) {
return array(
'parameters' => array(
'upload_tmp_dir' => ini_get('upload_tmp_dir')
)
);
}
}
I can't find an example showing how to use this loader in a PHP,XML,YAML configuration file with the imports directive.
Is there any example available using imports?
Is the ClosureLoader compatible with the YAML format?
There is an example available that shows how to use the Symfony\Component\Routing\Loader\ClosureLoader to load a route collection ( Routes as Closures).
But it does not show how to use the closure with the imports directive as the documentation states.
The idea behind my question is that it might be possible to access PHP's configuration values or some class constants in config.yml without creating an extension/compiler-pass or importing a file in a different configuration format. ( i.e. accessing constants is not possible in YAML format ).
This would open up some great possibilities ...
... like adding a closure that imports a parameter for the upload_tmp_dir path in php.ini that can instantly be used in LiipMonitorBundle's liip_monitor.checks.writable_directory array afterwards.
I've been able to use that loader in AppKernel:
class AppKernel extends \Symfony\Component\HttpKernel\Kernel
{
// ...
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml');
// Load config from the closure
$loader->load(function () {
// ..
});
}
}
The problem is that this is not taken into account when recomputing the cache (i.e. if you change your closure, the cache will not change).
to use an ini file you can juste call the file as ressource:
- { resource: parameters.ini }
theres 4 type of closure with the symfony dependcyInjection Component (Symfony 2.3). there are IniFileLoader, PhpFileLoader, XmlFileLoader and YamlFileLoader.
To use a personal closure you should create you personal closure that extends from
Symfony\Component\DependencyInjection\Loader\FileLoader
This a good exemple : http://www.adayinthelifeof.nl/2013/01/30/custom-symfony2-config-loader/
How can i create a link to the current in my template?
I want to create a language switcher which should link to the current page in varios languages, so all parameters should be the same exept for the locale.
I end up rolling my own function for this. I though at first it was included somewhere in FrameworkBundle but did not find anything about it. Here the steps I took.
At first, I created a Twig extension function that would output the same route as the one the user is visiting currently (parameters and query string included). I left this step to you. You can look at this link from a good tutorial on Symfony2 for the description of how to create a Twig extension if you don't know how already. I could help you with it if you need it.
Next step is to create the function itself that will switch the locale of the current route. This function will need the Request and Router objects as dependencies. In my personal case, I put this function in a dedicated service named RoutingHelper service. This service is then used by my Twig extension function. Here the service definition I added to the dependency container:
acme.helper.routing:
class: Application\AcmeBundle\Helper\RoutingHelper
scope: "request"
arguments:
request: "#request"
router: "#router"
And the constructor of my service:
protected $request;
protected $router;
public function __construct($request, $router)
{
$this->request = $request;
$this->router = $router;
}
The $locale parameter is new locale would like to switch to. Here the function:
public function localizeCurrentRoute($locale)
{
$attributes = $this->request->attributes->all();
$query = $this->request->query->all();
$route = $attributes['_route'];
# This will add query parameters to attributes and filter out attributes starting with _
$attributes = array_merge($query, $this->filterPrivateKeys($attributes));
$attributes['_locale'] = $locale;
return $this->router->generate($route, $attributes);
}
Essentially, it does what others have put so far but it also handles parameters and query string. The method filterPrivateKeys will remove private attribute from the route attributes. Those attributes are the one starting with an underscore and should not be passed back to the route generator. Here its defintion:
private function filterPrivateKeys($attributes)
{
$filteredAttributes = array();
foreach ($attributes as $key => $value) {
if (!empty($key) && $key[0] != '_') {
$filteredAttributes[$key] = $value;
}
}
return $filteredAttributes;
}
In the end, I'm able to this in my Twig view to create links to switch locales:
{% block language_bar %}
English
Français
{% endblock %}
Edit:
Here my twig extension service definition:
acme.twig.extension:
class: Application\AcmeBundle\Twig\Extension\AcmeExtension
arguments:
container: "#service_container"
tags:
- { name: twig.extension }
And in the twig extension function I have this call: $routingHelper = $this->container->get('acme.helper.routing');
This should solve the scope widening exception happening because the twig extension is not in the request scope.
Update:
It is now possible with Symfony 2.1 to have a locale switcher in an easier way than before. Indeed, the 2.1 version of Symfony introduced a new parameter for routes that make it more easy to do a locale switcher. Here the code, all in twig
{% set route_params = app.request.attributes.get('_route_params') %}
{# merge the query string params if you want to keep them when switching the locale #}
{% set route_params = route_params|merge(app.request.query.all) %}
{# merge the additional params you want to change #}
{% set route_params = route_params|merge({'_locale': 'fr'}) %}
{{ path(app.request.attributes.get('_route'), route_params) }}
It is still a few lines of twig code, but could be included in a Twig block for easier reuse. Credits to stof, from the Symfony community, for the code above.
Hope this is what you are looking for.
Regards,
Matt
Current page
Similar question: language switching without changing the current page
English