I want to open my websites like these:
http://127.0.0.1:8000/ (Works)
http://127.0.0.1:8000/en/ (Works)
http://127.0.0.1:8000/en/mrg (Works)
http://127.0.0.1:8000/mrg (Doesn't Work)
So I put this code in routing.yml:
teach:
resource: "#TeachBundle/Controller/"
type: annotation
prefix: /{_locale}
requirements:
_locale: "|en|fa"
and my controller is like this:
/**
* #Route("/mrg")
*/
public function mrgAction(Request $request)
{
$lang=$request->getLocale();
return new Response("<html><body>Your language: <b> $lang </b></body></html>");
}
All urls worked but http://127.0.0.1:8000/mrg doesn't work and returns:
No route found for "GET /mrg"
I need use default language for example if I try to open http://127.0.0.1:8000/mrg then open http://127.0.0.1:8000/en/mrg.
Is there any solution to fix this problem?
Add defaults option to your routing configuration to set the default locale if it's not set in your controllers #Routes:
teach:
resource: "#TeachBundle/Controller/"
type: annotation
prefix: /{_locale}
requirements:
_locale: "|en|fa"
defaults:
_locale: 'en' # or '%locale%'
Try this:
{_locale}
/**
* #Route("/{_locale}/mrg")
*/
public function mrgAction(Request $request)
{
$lang=$request->getLocale();
return new Response("<html><body>Your language: <b> $lang </b></body></html>");
}
Setting a Default Locale
# app/config/config.yml
framework:
default_locale: en
If doesn't work, Can You show your app/config/routing.yml.
I advice you to use : BeSimpleI18nRoutingBundle
https://github.com/BeSimple/BeSimpleI18nRoutingBundle
use BeSimple\I18nRoutingBundle\Routing\Annotation\I18nRoute;
class NoPrefixController
{
/**
* #I18nRoute({ "en": "/welcome", "fr": "/bienvenue", "de": "/willkommen" }, name="homepage")
*/
public function indexAction() { }
}
Here is the scheme of the required URLs:
/service/getBalance should map to CustomerController::getBalance
/service/addBalance should map to CustomerController::addBalance
/customer/getBalance should map to CustomerController::getBalance
/customer/addBalance should map to CustomerController::addBalance
Here is a simple controller
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class CustomerController extends Controller {
/**
* #Route("/getBalance")
*/
public function getBalanceAction(Request $request) {
}
/**
* #Route("/addBalance")
*/
public function addBalanceAction(Request $request) {
}
} // class CustomerController
Have tried the following ways. None of them worked.
# rounting.yml
v1:
resource: "#AppBundle/Controller/CustomerController.php"
prefix: /service
type: annotation
v2:
resource: "#AppBundle/Controller/CustomerController.php"
prefix: /customer
type: annotation
loading the same resource with different prefix always overrides the previous occurrence (the last one works). The following also doesn't work for the same reason and have the same behavior.
# rounting.yml
v1:
resource: "#AppBundle/Resources/config/routing_customer.yml"
prefix: /service
v2:
resource: "#AppBundle/Resources/config/routing_customer.yml"
prefix: /customer
# routing_customer.yml
getBalance:
path: /getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
Third not working option:
# rounting.yml
v1:
resource: "#AppBundle/Resources/config/routing_v1.yml"
prefix: / # evenr putting /service here instead of inside
v2:
resource: "#AppBundle/Resources/config/routing_v2.yml"
prefix: / # evenr putting /customer here instead of inside
# routing_v1.yml
getBalance:
path: /service/getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /service/addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
# routing_v2.yml
getBalance:
path: /customer/getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /customer/addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
I actually need to route / and /customer to the same controller:
/getBalance and /customer/getBalance.
I want to give two prefixes for a group of methods. How to do that in Symfony?
Conclusion from my trials, #goto's answer and #Cerad's comments:
The last Example above could have worked if I used different route names. Route names are unique though out the whole project (Not just unique in file). v1_getBalance and v2_getBalance.
The other solution is to use a custom loader as #goto described.
You could do routes this way:
#Route(
"/{subject}/getBalance",
requirements={
"subject": "customer|service"
}
)
in yml:
subject_getbalance:
path: /{subject}/getBalance
requirements:
subject: customer|service
The requirement is safer than nothing: it allows you to route another route like foo/getBalance on another controller (as it does not match the requirement)
EDIT: for your special case, as you need /getBalance to map to your route too you could do:
subject_getbalance:
path: /{subject}/getBalance
default: { _controller: YourBundle:Controller }
requirements:
subject: customer|service
default_getbalance:
path: /getBalance
default: { _controller: YourBundle:Controller, subject: customer }
Edit: the last idea is to a custom route loader (but I've never tried):
class ExtraLoader extends Loader
{
public function load($resource, $type = null)
{
/* ... */
$prefixes = [ 'default_' =>'','customer_' =>'/customer','service_' =>'/service']
// prepare a new route
$path = '/getbalance/{parameter}';
$defaults = array(
'_controller' => 'YourBundle:Actiona',
);
$requirements = array(
'parameter' => '\d+',
);
foreach($prefixes as $prefixName => $prefixRoute) {
$route = new Route($prefixRoute . $path, $defaults, $requirements);
$routes->add($prefixName . 'getBalance', $route);
}
This will allows you to have 3 routes generated:
default_getBalance: /getBalance
customer_getBalance: /customer/getBalance
service_getBalance: /service/getBalance
Settings:
Symfony 3
To stay simple, I will refer to a simple AppBundle, with Entity1 and Entity2 as entities.
There are no specific parameter per entity, just an id.
Entity2 is a child of Entity1, which mean that in the SQL diagram, Entity2 have a foreign key entity1_id.
Summary:
I'm trying to build the following route:
/entity1/{id}/entity2/{id}/show
Where the first {id} is the id of Entity1, and the second of Entity2.
My .yml files:
entity1.yml
entity1_index:
path: /
defaults: { _controller: "AppBundle:Entity1:index" }
methods: GET
entity1_show:
path: /{id}/show
defaults: { _controller: "AppBundle:Entity1:show" }
methods: GET
entity1_new:
path: /new
defaults: { _controller: "AppBundle:Entity1:new" }
methods: [GET, POST]
entity1_edit:
path: /{id}/edit
defaults: { _controller: "AppBundle:Entity1:edit" }
methods: [GET, POST]
entity1_delete:
path: /{id}/delete
defaults: { _controller: "AppBundle:Entity1:delete" }
methods: DELETE
# ENTITY2
entity2:
resource: "#AppBundle/Resources/config/entity2.yml"
prefix: /{id}/entity2
entity2.yml
entity2_index:
path: /
defaults: { _controller: "AppBundle:Entity2:index" }
methods: GET
entity2_show:
path: /{id}/show
defaults: { _controller: "AppBundle:Entity2:show" }
methods: GET
entity2_new:
path: /new
defaults: { _controller: "AppBundle:Entity2:new" }
methods: [GET, POST]
entity2_edit:
path: /{id}/edit
defaults: { _controller: "AppBundle:Entity2:edit" }
methods: [GET, POST]
entity2_delete:
path: /{id}/delete
defaults: { _controller: "AppBundle:Entity2:delete" }
methods: DELETE
Problem:
Route pattern cannot reference variable more than once, which is here my problem.
I don't know what to do so that Symfony can differentiate each {id}.
I suggestion you use Route annotations instead. I personally find it much easier to use.
For example, you could do something like this:
/**
* #Route("/editEntity1/{id1}/entity2/{id2}",
* defaults={"id1" = 0,"id2" = 0},
* name="editEntity1Route")
*/
public function editEntity1Action($id1, $id2, Request $request){
...
// Now you can use both id variables like so:
$eName1 = $id1->getName();
$eName2 = $id2->getName();
...
}
I renamed the route 'editEntity1Route' because it explicitly tells you what is does. In this case Edit Enitity 1. Then in you controller you would have other routes for "showEntity1", "newEntity1" etc...
In another controller the easy way to redirect to the above route is like so:
...
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('e1')
->from('AppBundle:Entity1', 'e1')
->where('e1.e1_name = :e1_name') // Example
->setParameter('e1_name', "sample name");
$entity1 = $qb->getQuery()->setMaxResults(1)->getOneOrNullResult();
...
$entity2 = $qb->getQuery()->setMaxResults(1)->getOneOrNullResult();
return $this->redirectToRoute('editEntity1Route', array(
'id1' => $entity1->getId(),
'id2' => $entity2->getId(),
));
Also, in Twig it is very easy to setup a link to the route:
<a href="{{ path('editEntity1Route',
{'id1':entity1.getId, 'id2':entity2.getId}) }}">Edit Entity1</a>
In the above twig file, this presumes from your controller you've passed in the variables 'entity1' and 'entity2'.
I think this might give you some ideas on how to achieve this if you use routing annotation. You could still use routes in the Yaml files, I just find it more obvious using routing annotations.
Take a look at your entity1.yml
entity2:
resource: "#SalonBundle/Resources/config/dashboard/soushall.yml"
prefix: /{id}/soushall
Try remove these {id}, so the route becomes /entity1/entity2/{id}/show.
Now, your {id} is the id from Entity2. Since Entity2 have a foreign key entity1_id that linked to the id from Entity2, it is enough for the route to just read one id from Entity2.
Hewwo~
Thanks for the details Alvin.
I haven't tried annotation routing yet, I'm not familiar with it yet.
I will keep that post marked, as of now, I already made too many routes to switch to annotation routing.
But I will try for my next project... ;)
Meanwhile, I figured out how to solve my problem.
Thus, here are the details.
Settings: Same as the first post.
Solution:
Rename route variables:
• entity1.yml
entity1_index:
path: /
defaults: { _controller: "AppBundle:Entity1:index" }
methods: GET
entity1_show:
path: /{idEntity1}/show
defaults: { _controller: "AppBundle:Entity1:show" }
methods: GET
entity1_new:
path: /new
defaults: { _controller: "AppBundle:Entity1:new" }
methods: [GET, POST]
entity1_edit:
path: /{idEntity1}/edit
defaults: { _controller: "AppBundle:Entity1:edit" }
methods: [GET, POST]
entity1_delete:
path: /{idEntity1}/delete
defaults: { _controller: "AppBundle:Entity1:delete" }
methods: DELETE
# ENTITY2
entity2:
resource: "#AppBundle/Resources/config/entity2.yml"
prefix: /{idEntity1}/entity2
• entity2.yml
entity2_index:
path: /
defaults: { _controller: "AppBundle:Entity2:index" }
methods: GET
entity2_show:
path: /{idEntity2}/show
defaults: { _controller: "AppBundle:Entity2:show" }
methods: GET
entity2_new:
path: /new
defaults: { _controller: "AppBundle:Entity2:new" }
methods: [GET, POST]
entity2_edit:
path: /{idEntity2}/edit
defaults: { _controller: "AppBundle:Entity2:edit" }
methods: [GET, POST]
entity2_delete:
path: /{idEntity2}/delete
defaults: { _controller: "AppBundle:Entity2:delete" }
methods: DELETE
Rename $id in entities:
• Entity1.php
private $id; to private $idEntity1;
*• Entity2.php
private $id; to private $idEntity2;
Edit the controllers:
[...] indicate that code was skipped, thus not edited.
• Entity1Controller.php
newAction changes:
return $this->redirectToRoute('entity1_show', array('id' => $entity1->getId()));
to
return $this->redirectToRoute('entity1_show', array('idEntity1' => $entity1->getId()));
For each redirectToRoutewe find, we will rename the id variable to match our route/entity variable.
editAction changes:
public function editAction(Request $request, Entity1 $entity1)
{
[...]
if ($editForm->isSubmitted() && $editForm->isValid()) {
[...]
return $this->redirectToRoute('entity1_edit', array('idEntity1' => $entity1->getId()));
}
[...]
}
• Entity2Controller.php:
In every function, we will add our parent entity as variable.
If not done, our routes won't works
indexAction changes:
public function indexAction()
{
[...]
}
to
public function indexAction(Entity1 $entity1)
{
[...]
return $this->render('AppBundle:Default:index.html.twig', array(
'entity1' => $entity1,
'entity2s' => $entity2s,
));
}
newAction changes:
public function newAction(Request $request, Entity1 $entity1)
{
[...]
if ($form->isSubmitted() && $form->isValid()) {
[...]
return $this->redirectToRoute('entity2_show', array(
'idEntity1'=>$entity1->getId(),
'idEntity2'=>$entity2->getId()
));
}
return $this->render('AppBundle:Default:new.html.twig', array(
'entity1' => $entity1,
'entity2' => $entity2,
'form' => $form->createView(),
));
}
showAction changes:
public function showAction(Entity1 $entity1, Entity2 $entity2)
{
$deleteForm = $this->createDeleteForm($entity1, $entity2);
return $this->render('AppBundle:Default:show.html.twig', array(
'entity1' => $entity1,
'entity2' => $entity2,
'delete_form' => $deleteForm->createView(),
));
}
editActionchanges
public function editAction(Request $request, Entity1 $entity1, Entity2 $entity2)
{
$deleteForm = $this->createDeleteForm($entity1, $entity2);
[...]
if ($editForm->isSubmitted() && $editForm->isValid()) {
[...]
return $this->redirectToRoute('entity2_edit', array(
'idEntity1'=>$idEntity1,
'idEntity2'=>$entity2->getId()
));
}
return $this->render('AppBundle:Default:edit.html.twig', array(
'entity1' => $entity1,
'entity2' => $entity2,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
deleteAction changes:
public function deleteAction(Request $request, Entity1 $entity1, Entity2 $entity2)
{
$form = $this->createDeleteForm($idEntity1, $entity2);
[...]
return $this->redirectToRoute('entity2_index', array('idEntity1' => $entity1->getId()));
}
createDeleteFormchanges
private function createDeleteForm(Entity1 $entity1, Entity2 $entity2)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('entity2_delete', array('idEntity1' => $entity1->getId(), 'idEntity2' => $entity2->getId())))
->setMethod('DELETE')
->getForm()
;
}
This sum up all the changes needed...
As long as you can replace code through a whole project, it's quite fast to do...
Thank you Alvin and david for your replies.
While I didn't ended up using them, I'm sure they will be usefull in the future.
Be it for me or for someone else... :)
This topic is now solved... ^^
I'm trying to internationalize my website using Symfony.
This is my routing.yml:
index:
pattern: /{_locale}
defaults: { _controller: AppBundle:Index:index, _locale: en }
requirements:
_locale: en|fr
When the URL is just "/", "en" locale is set automatically, this is great but I want the browser locale.
For exemple, if I'm in France and I type "/", I want redirect to "/fr/", etc.
Can you help me?
you can get client locale and set redirection in controller
$clientLocale = strtolower(str_split($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2)[0]);
switch ($clientLocale) {
case 'fr':
return $this->redirect($this->generateUrl('fr_route'));
break;
default:
return $this->redirect($this->generateUrl('en_route'));
break;
}
Based on b3da answer, I'll apply it only for the index route (as I think that is the main case when someone type your domain without params) and relying on my YML translations:
#routing.yml
index:
path: /
defaults:
_controller: AppBundle:Pub:index
index2:
path: /{_locale}
defaults:
_controller: AppBundle:Pub:index
#PubController.php
public function indexAction($_locale=null, Request $request) {
if (!$_locale) {
$browserLocale = strtolower(str_split($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2)[0]);
return $this->redirect($this->generateUrl('index2', ['_locale' => $browserLocale]));
}
return $this->render('AppBundle::index.html.twig', []);
}
If the local browser is not translated on your app/Resources/translation YMLs then it will render the texts using your fallback locale (app/config/parameters.yml).
I have been trying to follow this tutorial "http://fr.openclassrooms.com/informatique/cours/developpez-votre-site-web-avec-le-framework-symfony2" . When I try to test their functions i get this error.
No route found for "GET /voir/5"
# \src\MonBlog\BlogBundle\Resources\config\routing.yml
monblogblog_homepage:
pattern: /hello/{name}
defaults: { _controller: MonBlogBlogBundle:Default:index }
monblogblog_accueil:
path: /
defaults: { _controller: MonBlogBlogBundle:Default:index }
monblogblog_voir:
path: /voir/{id}
defaults: { _controller: MonBlogBlogBundle:Default:voir }
monblogblog_ajouter:
path: /ajouter
defaults: { _controller: MonBlogBlogBundle:Default:ajouter }
monblogblog_modifier:
path: /modifier/{id}
defaults: { _controller: MonBlogBlogBundle:Default:modifier }
monblogblog_supprimer:
path: /supprimer/{id}
defaults: { _controller: MonBlogBlogBundle:Default:supprimer }
MON CONTROLEUR \SY\src\MonBlog\BlogBundle\Controller\DefaultController.php
<?php
namespace MonBlog\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction($name)
{
return $this->render('MonBlogBlogBundle:Default:index.html.twig', array('name' => $name));
}
public function voirAction($id)
{
return $this->render('MonBlogBlogBundle:Blog:voir.html.twig', array(
'id' => $id,
));
}
public function ajouterAction()
{
if($this->get('request')->getMethod() == 'POST')
{
$this->get('session')->getFlashBag()->add('notice','Article bien enregistré');
return $this->redirect( $this->generateUrl('monblogblogaccueil', array('page' => 5)) );
}
return $this->render('MonBlogBlogBundle:Blog:ajouter.html.twig');
}
public function modifierAction($id)
{
return $this->render('MonBlogBlogBundle:Blog:modifier.html.twig');
}
public function suprrimerAction($id)
{
return $this->render('MonBlogBlogBundle:Blog:supprimer.html.twig');
}
}
Two suggestions:
1) Have you cleared your cache?
2) Are you sure that the bundle's routing file (\src\MonBlog\BlogBundle\Resources\config\routing.yml) is being imported in the app's main routing file (app/config/routing.yml)?
There are two helpful command line tools to help with routing:
1) php app/console router:match /voir/5
2) php app/console router:debug