I'm a beginner in Symfony2 and I'm just wondering if the consistency of args has to be done myself in the controller or if there is a mechanism i don't know of
let's take a example:
i have a route like /company/id/user/id to display some information for the user
i have tried manually to change id for either company or user and there is no error if the user is not from the company ?!
Do i have to check in the controller displayUserAction if user and company are bound ?
/**
* #Route("/company/{company_id}/user/{site_id}")
* #ParamConverter("company", class="MyModel\Company", options={"mapping": {"company_id": "id"}})
* #ParamConverter("site", class="MyModel\User", options={"mapping": {"site_id": "id"}})
*/
public function displayUserAction(Company $company, User $user)
{
..
}
routing.yml
user_info:
path: /company/{company_id}/user/{site_id}
defaults: { _controller: UserBundle:Default:displayUser }
Edit:
I've found another way : map using several criteria
/**
* #Route("/company/{company_id}/user/{site_id}")
* #ParamConverter("company", class="MyModel\Company", options={"mapping": {"company_id": "id"}})
* #ParamConverter("site", class="MyModel\User", options={"mapping": {"site_id": "id", "company_id":"company"}})
*/
public function displayUserAction(Company $company, User $user)
{
..
}
You can re-order the arguments in the Action all you like. Symfony is smart enough to match the arguments - but you should keep the naming somewhat consistent - which you have done anyway. Symfony will match {company_id} in your route to $company in your Action for example no matter the order you place them in.
In your route, both arguments are required for the route to match. So the route will only match work if both arguments are bound.
In your Action, you would need to check the User belongs to the Company. The architecture of the Route and the Action don't care if the 2 entities are related, they only care that a value has been supplied.
Related
I've set up my entities, now I want to
use the doctrine:generate:crud, during this command it asks what route
prefix I would like. I would expect that this means that the routes
would automatically be generate, this is not happening. So I need to
know if it is supposed to generate the routes, or if I'm supposed to
create them all manually? If it is the case that I need to generate
them manually is there a route class, to define all the routes for the
CRUD operations?
When you generate a CRUD with Symfony, it will ask you to choose a configuration format.
By default, it's annotation. If you haven't changed it, then your routes are in the entity controller, as annotation.
In the example below, you can see the #Route anotation, which is how to define the URL in anotation.
/**
* Finds and displays a user entity.
*
* #Route("/user/{id}", name="user_show")
* #Method("GET")
*
* #param User $user
* #return \Symfony\Component\HttpFoundation\Response
*/
public function showAction(User $user) {
$deleteForm=$this->createDeleteForm($user);
return $this->render('security/show.html.twig', array(
'security'=>$user,
'delete_form'=>$deleteForm->createView(),
));
}
In the end, it's not that "It didn't happen", it's simply and most likely that you haven't read some doc, and didn't knew about it... ;)
Symfony doc: Routing
I work with symfony 2.8 and FOSUserBundle, I have two type of user in the same table in database , And I like to differenciate the registration form in the same page of registration like this :
*
the problem that I can't use two instance of the form in the same page, what can I do please?
The way I would go about this, is override FOSUserBundle and then extend the RegistrationController and likely the corresponding template.
In the registerAction you can reuse some parts of the original, but where the form is created you then create two different ones, maybe like this:
/** #var $formFactory FactoryInterface */
$clientFormFactory = $this->get('client_registration.form.factory');
$clientForm = $clientFormFactory->createForm();
$clientForm->setData($client);
/** #var $formFactory FactoryInterface */
$correspondentFormFactory = $this->get('correspondent_registration.form.factory');
$correspondentForm = $correspondentFormFactory->createForm();
$correspondentForm->setData($correspondent);
$clientForm->handleRequest($request);
$correspondentForm->handleRequest($request);
if ($clientForm->isSubmitted() && $clientForm->isValid()) {
// ...
} elseif ($correspondentForm->isSubmitted() && $correspondentForm->isValid()) {
// ...
}
return $this->render(
'#FOSUser/Registration/register.html.twig',
[
'clientForm' => $clientForm->createView(),
'correspondentForm' => $correspondentForm->createView(),
]
);
The part inside the if conditions will then probably look similar as to the original controller. You might have different UserManager's for each user type, you have to switch out, but other than that it's basically: dispatch pre-event, save user, dispatch post-event, redirect. It is important that you dispatch both events as other parts of FOSUserBundle will rely on them, e.g. sending a registration email.
In your template you then just render both forms in their tab. You might have to fiddle around with the form id's a bit, but that should be straightforward.
Hi I am using Doctrine with DoctrineBehaviors bundle in order to log history of changes for entities. Everything is working fine except one thing. I will need information where is the location of change that is going to be saved. For example if that change happened in cron command or in front end controller by some user etc.
Logging class is looking like this (similar to this) :
/** service: "entity_logger" **/
class EntityLogger
{
/**
* #var EntityManager
*/
protected $em;
public function __construct(EntityManager $em = null)
{
$this->em = $em;
}
function __invoke($message)
{
$this->em->persist(new LogMessage($message));
$this->em->flush();
}
}
and it's set as service. So my question is how to manage information of location of change? I will need somehow to send beside entity that is going to be persist one more thing: location of that change. As I see it there are at least two options :
A) store value of location to that service "entity_logger" before persist/flush happens. Have property "location" inside service and put it into LogMessage obj. Something like:
$this->get('entity_logger')->setCurrentLocation("Cron for sync");
$this->em->persist($entityOne);
$this->em->flush();
B) get stack trace and see what class has call persist/flush and then see how to handle that information
First option requires editing of all current locations of persist and second one don't have that overhead but what is the better approach?
Is there even better way of doing that?
Thanks
I have just started using Symfony and I am having a routing problem. Here is the routing fromt the controller:
/**
* #Route("/social/{name}/", name="_speed1")
* #Route("/social/drivers/")
* #Route("/social/drivers/{name}/", name="_driver")
* #Route("/social/", name="_speed")
* #Template()
*/
public function unlimitedAction()
{
If I go to speed/social/ or speed/social/bob or speed/social/drivers/ or speed/social/drivers/bob all of those pages render with no problem. However I need the name being passed in so I changed
public function unlimitedAction()
{
to
public function unlimitedAction($name)
{
If I go to speed/social/drivers/ or speed/social/drivers/bob it returns fine. However, if I go to speed/social/ then I get the following error:
Controller "MyBundle\Controller\DefaultController::unlimitedAction()"
requires that you provide a value for the "$name" argument (because there is
no default value or because there is a non optional argument after this one).
I can't understand why it works for one route but not the other.
So my question is, how can I acheive my routing so that I can go to:
speed/social/
speed/social/drivers/
speed/social/drivers/bob
And be able to pass the variable to the action without error.
Thanks!
To answer your question: you have to provide a default value for name parameter, for each route without the {name} parameter in the url. I can't test it right now and I can't remember the syntax when using annotations, but should be something like this:
/**
* #Route("/social/{name}/", name="_speed1", defaults={"name"=null})
* #Route("/social/drivers/{name}/", name="_driver", defaults={"name"=null})
* #Template()
*/
public function unlimitedAction($name)
{
}
This way you should be able to call /social/ and /social/foo as well as /social/drivers/ and /social/drivers/foo.
But, really, this is not the right way to go. Just define more actions, each binded to a single route:
/**
* #Route("/social", name="social_index")
* #Template()
*/
public function socialIndexAction() { } // /social
/**
* #Route("/social/{name}", name="social_show")
* #Template()
*/
public function socialShowAction($name) { } // /social/foo
As a general rule, each method (each action) should be focused to do just one thing and should be as short as possible. Use services and make your controllers do what they are supposed to do: understand user input, call services and show views.
I have an action inside my controller class and I want two different routes like below:
/**
* Displays a form to create a new entity.
*
* #Route("/edit/choose/date", name="user_choose_date")
* #Route("/supervisory/choose/date", name="sup_choose_date")
* #Template()
*/
public function chooseDateAction()
{
return array( );
}
The reason for that I would like to give the route access to some users but the user role are different.
Let's say:
User with supervisor role can access sup_choose_date
User with user role can access user_choose_date
The question is if it is possible to have two different routes for one action? or I have duplicate the code for different routes ?
Yes, it is possible when using YAML (or XML) routing.
Example:
sup_choose_date:
pattern: /supervisory/choose/date
defaults: { _controller: MyBundle:Default:chooseDate }
user_choose_date:
pattern: /edit/choose/date
defaults: { _controller: MyBundle:Default:chooseDate }
Worked for me!
You must set different names; if not, specify explicitly
I is possible on every kind of format including annotation. It should work as long as you have different name for every route.