I am using symfony and I want to get the url of a specific route ,
my route is like this
project_sign_in:
pattern: /signin
defaults: { _controller: ProjectContactBundle:User:signIn }
i want to generate the url from this route so i can get
localhost/app_dev.php/signin
or {SERVER-ADDRESS}/app_dev/signin
if I was browsing the server.
Using the Routing Component at version 4.0:
<?php
use Symfony\Component\Routing\Generator\UrlGenerator;
UrlGenerator->generate('project_sign_in', [], UrlGenerator::ABSOLUTE_URL);
The last facultative parameter has to be true to generate absolute url:
$router->generate('project_sign_in', array(), true);
in twig:
{{ path('project_sign_in', {}, true) }}
{# or #}
{{ url('project_sign_in') }}
in controller:
$this->generateUrl('project_sign_in', array(), true );
EDIT: for symfony 4, see #Michael B. answer
UrlGenerator->generate('project_sign_in', [], UrlGenerator::ABSOLUTE_URL);
In Symfony 5.0, if you are using Routing within a service:
namespace App\Service;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
.
.
.
private $router;
public function __construct(UrlGeneratorInterface $router)
{
$this->router = $router;
}
public function foo()
{
$this->router->generate('bar', [], urlGeneratorInterface::ABSOLUTE_URL);
}
Related
I created a custom module to create a /store/ID/tasks page
https://www.drupal.org/project/commerce
How to limit access to this page to the store owner ?
If the current user is owner of store ID 76, he can access this page :
/store/76/tasks
But if he goes to another store, he must have denied access :
/store/89/tasks
https://git.drupalcode.org/sandbox/zenimagine-3076032
task_notify/task_notify.routing.yml
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
task_notify/src/Controller/TaskNotifyStoreController.php
<?php
namespace Drupal\task_notify\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\commerce_store\Entity\StoreInterface;
class TaskNotifyStoreController extends ControllerBase {
public function Tasks() {
return [
'#theme' => 'task_notify_store_template',
];
}
public function taskAccess(StoreInterface $store, AccountInterface $account = NULL, $return_as_object = FALSE) {
$result = $store->access('edit', $account, TRUE);
return $return_as_object ? $result : $result->isAllowed();
}
}
This page should be accessible only if the current user can edit the store (the site administrator and the store owner).
Access in the module code must have the same conditions as in this view :
https://i.stack.imgur.com/ZfUMo.png
I was inspired by the two files below :
https://git.drupalcode.org/project/commerce_marketplace/-/blob/8.x-1.x/src/Plugin/Action/MarketplaceIncreaseStoreLimitByOne.php
https://git.drupalcode.org/project/commerce_marketplace/-/blob/8.x-1.x/src/Plugin/Action/MarketplaceMarkAsDefault.php
In this case, we can tell Drupal that {store} is an entity and it will load the object. So we don't have to do that in the Controller function.
So your routing file can include "parameters" settings to do that.
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
options:
parameters:
store:
type: entity:commerce_store
Now your controller function has access to that object.
public function Tasks(StoreInterface $store) { ...
In my experience, that is NOT true of the access() method (at least when using a type-hinted parameter as we are doing here). You get a string, so you'll have to load the store manually.
public function taskAccess(string $store, AccountInterface $account) {
$store = \Drupal\commerce_store\Entity\Store::load($store);
// Check store owner against current user.
if ($store->access('edit', $account)) {
return AccessResult::allowed();
}
else {
return AccessResult::forbidden();
}
Also we need to define $account in the routing file now, as we are using type-hinted parameters (I think). So add that to the options:.
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
options:
parameters:
store:
type: entity:commerce_store
account: \Drupal\Core\Session\AccountProxy
$account is one of a few special parameters that we can type-hint this way. More info: https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes/advanced-route-access-checking
class DefaultController extends Controller
{
public function indexAction($page, $name) {
return $this->render('default/new.html.php'
// , array(
// $name => 'bob'
// )
);
}
}
new.html.php
<p>Welcome to the index <?= $name; ?></p>
When I use this code it is returning an error message.
But,
<p>Welcome to the index {{ name }}
this returns me correct output.
I want to use .html.php instead of .html.twig
I am going through this https://symfony.com/doc/3.4/templating/PHP.html
routing.yml
app:
path: /dd
defaults:
_controller: AppBundle:Default:index
page: 1
name: "bob"
config.yml
framework:
# ...
templating:
engines: ['twig', 'php']
Note: I am using ubuntu16.04 and Symfony 3.4
Tried locally according to Symfony documentation:
/**
* #Route("/test", name="test_route")
*/
public function test()
{
return $this->render(
'test.html.php',
[
'test_var' => 'Hello test',
]
);
}
My test.html.php:
<?php
echo $test_var;
This outputs Hello test.
PS: Tried get_defined_vars();, the variable should be seen there.
I have a route
detail:
path: /{code}
defaults: { _controller: controller.main:detailAction }
I also have a controller for this route
public function detailAction(Request $request, string $code, int $size, array $params): Response
{
}
My question is: how can I say to controller which parameters he should take as int $size and array $params ? I have found in symfony docs that I may specifically mention params in defaults section with default values like this
detail:
path: /{code}
defaults: { _controller: controller.main:detailAction }
size: 1
params: "Hello world!"
But that is not what I want since I shouldn't have a default value for this params but it ought to be taken directly from request. How do I do this without making my route like /{code}/{size} ?
And even in this case what do I do with an array?
You can generate a url like this by passing parameters in your controller:
$url = $this->generateUrl("detail", array("code" => $code, ...));
return $this->redirect($url);
And routing:
detail:
path: /
defaults: { _controller: controller.main:detailAction }
If you want to specify parameters like this
someurl.io/action/?filter=allopenissues&orderby=created
You should typehint Request object in your action and access its query parameters bag. If your controller extends Symfony Controllers, Request will be automatically passed.
use Symfony\Component\HttpFoundation\Request;
....
public function updateAction(Request $request)
{
$request->query->get('myParam'); // get myParam from query string
}
In Symfony1 i can:
blog:
url: /blog/slug
param: { module: blog, action: index }
and in action/controller i can get slug with: $request->getParameter('slug');
In Symfony2:
blog:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
and i create "components" same as Symfony1 - http://symfony.com/doc/current/book/templating.html#templating-embedding-controller
How can i get slug in embedding controller? I tried:
$request->query->get('foo');
$request->request->get('bar');
but this still return null. In AcmeBlogBundle:Blog:show controller working ok.
The param converter will populate the argument with the string from the route. So here is what your method looks like.
class BlogController extends Controller {
public function showAction($slug) {
// $slug will contain the value of the string from the route
}
}
So if you wanted to embed this into a twig template it would look like this:
{{ render( controller('AcmeBlogBundle:Blog:show', {'slug': 'this-is-the-slug' })) }}
or from another controller
$this->render('AcmeBlogBundle:Blog:show.html.twig', array('slug' => 'this-is-the-slug'));
Is it possible to use global variable from config.yml in translation file in symfony 2?
If yes, please can you give some example or useful link?
For injecting a (or all) twig globals into your translations you need to override the translation service. Check out this answer if you want a detailed explanation. Here is what I did:
Override the translator.class parameter (e.g. in your parameters.yml):
translator.class: Acme\YourBundle\Translation\Translator
Create the new Translator service:
use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;
class Translator extends BaseTranslator
{
}
Finally override both trans and transChoice:
/**
* {#inheritdoc}
*/
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
return parent::trans(
$id,
array_merge($this->container->get('twig')->getGlobals(), $parameters),
$domain,
$locale
);
}
/**
* {#inheritdoc}
*/
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
{
return parent::transChoice(
$id,
$number,
array_merge($this->container->get('twig')->getGlobals(), $parameters),
$domain,
$locale
);
}
In this example I am injecting all twig globals. You can only inject one like this:
array_merge(['%your_global%' => $this->container->get('twig')->getGlobals()['your_global']], $parameters)
You can follow those 2 simple steps:
Inject a Global variable in all the templates using the twig configuration:
# app/config/parameters.yml
parameters:
my_favorite_website: www.stackoverflow.com
And
# app/config/config.yml
twig:
globals:
my_favorite_website: "%my_favorite_website%"
Use Message Placeholders to have the ability to place your text in your translation:
# messages.en.yml
I.love.website: "I love %website%!!"
# messages.fr.yml
I.love.website: "J'adore %website%!!"
You now can use the following twig syntax in your templates to get your expected result:
{{ 'I.love.website'|trans({'%website%': my_favorite_website}) }}