symfony2 routing requirements combining 2 parameters - symfony

So I got this in my routing.yml:
requirements:
var1: \d+
var2: \d+
Both are checked on their own and valid.
I need to check the combination of the 2, since the combination is not always valid.
For this case I need to check the relation between 2 objects in the database, the first should be the parent of the second.
I can do this in the controller, but I don't really like that implementation. Also, I need this same check for more than 1 route.
How would I add another requirement that checks the combination? Can I define a method in the controller class that would be called?
Or would the best solution be something like:
public function indexAction($var1, $var2)
{
$result = $this->checkRelation($var1, $var2);
if ($result) {
// return errorpage
return $result;
}
// ...
}

So as I understand your question, you want the following:
/parent/child/ --> returns 200
/not_parent/not_child --> returns 404
The Symfony2 Routing component doesn't do this natively, but you could extend it.
http://symfony.com/doc/master/cmf/cookbook/using-a-custom-route-repository.html

The final solution I went with was the following:
add a method checkRelation that requires all parameters
run a query inside that method to check if everything is ok.
return false when there is a problem, return true when values are ok. (alternatively you can return an object or something)
in the action I check if the value is false, if so I return a generic "not found" page for the specific controller.
In all this is very similar to what I posted in my initial question.
When using the same checkRelation in multiple controllers it might be a good idea to move it (partially) to a repository-class or something similar to prevent duplication of code/logic.

Related

Symfony2 - Authentication lost after redirection

I've been experiencing an issue with my SF2 application today.
I want the user to be automatically authenticated after submiting a valid subscription form.
So basically in my controller here's what I do:
if ($form->isValid()) {
$customer = $form->getData();
try {
$customer = $this->get('my.service.manager.customer')->customerSubscribe($customer);
} catch (APIClientException $e) {
$error = $e->getErrors();
...
}
if ($customer && !isset($error)) {
// connect customer
$token = new UsernamePasswordToken($customer, null, 'api_auth', array('ROLE_USER'));
$this->get('security.context')->setToken($token);
...
}
return new RedirectResponse($this->generateUrl('MyBundle_index'));
}
The two lines below the 'connect customer' comment actually seem to authenticate the user fine.
The problem being when I redirect to another page with RedirectResponse, then the authentication is lost.
I've tried a call to
$this->container->get('security.context')->isGranted('ROLE_USER')
which returns true just before the call to RedirectResponse, and false in my other controller where the response is being redirected.
At this point I'm a bit confused about what I'm doing wrong. Any ideas appreciated.
Btw, I'm using Symfony2.1
I've noticed this happens when you redirect more than once at a time. Does the controller for the MyBundle_index route return another redirect? If so, I think that's your answer.
Otherwise, maybe try using forwards? Instead of:
return new RedirectResponse($this->generateUrl('MyBundle_index'));
...just forward to whatever controller/action is defined for that route:
return $this->forward("SomeBundle:Default:index");
The URL that the user ends up with in their address bar might not be what you're expecting (it won't change from the one they requested originally), but you can probably fiddle with that to get it to your liking.
Ok I solved it like so:
$token = new UsernamePasswordToken($customer->getEmail(), null, 'api_auth', array('ROLE_USER'));
Apparently I needed to pass the customer id (in that case the email) as the first argument of UsernamePasswordToken, instead of the entire customer object. I'm not sure why since my entity Customer has a _toString method implemented, but at least it works fine like that.

Grails data binding

A Grails controller received is called with the following request parameters:
defaultPrice[0].amount 22
defaultPrice[0].currency 1
defaultPrice[0].id
defaultPrice[1].amount 33
defaultPrice[1].currency 3
defaultPrice[1].id
I've defined the following command class:
class PriceCommand {
BigDecimal amount
Integer currency
Integer id
}
I attempt to bind the request parameters to a `List' in the action
def save = {List<PriceCommand> defaultPrice ->
}
But within the action, defaultPrice is null.
It requires an command with existing list of data, with specified name, that will be filled with data from request.
Try
import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.Factory
class PriceListCommand {
List<PriceCommand> defaultPrice = ListUtils.lazyList([], {new PriceCommand()} as Factory)
}
and use this command inside controller. It should works
I'm not sure if this is what your looking but it may help...
1.) I think indexed params only work if you have a parent-child or one-to-many relationship. For example you might need to introduce a PriceCommandParent which contains a list of PriceCommand. I may be wrong on this and I welcome any corrections.
2.) I've found that indexed params aren't as magically as some of the other areas of Grails/Groovy so sometimes i'd rather deal with the mapping myself. Below is how i've handled it in the past....
def things = []
params.each{name, value->
if (name.matches('^(thing\\[\\d+\\])$')){ //<-- look for 'thing[x]'
things.add(new Thing(params[name]);
}
}
Let me know if any of this is of help

When does the $op parameter of hook_search() get defined as 'search'?

Edit
The basic question here is "when does the $op parameter get defined as 'search'"?
I am trying to create a custom search in an implementation of hook_search(). I have been looking through the Drupal documentation for the method here: http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_search/6
I know the method is running because I can slip a die('killed inside of implementation of hook_search()') into the top of the function and see the output.
In the following code, the script is never killed so that I can see the output search caught inside of my_search(). This leads me to believe that the 'search' case of the switch statement is never firing. Does anybody know where I might go from here?
/**
* Implementation of hook_search()
*/
function my_search($op = 'search', $keys = NULL) {
switch($op)
{
case 'search':
die('search caught inside of my_search()');
break;
}
}
First things first.
Assuming your module is called 'my', try to go to URL /search/my/whatever - probably you will see access forbidden page (assuming you do not have anything more in your code besides what you have pasted in your question).
That's because you do not return anything when search module calls your hook with $op = 'name' (see _search_menu() in search.module). You need to return "a translated name defining the type of items that are searched for with this module ('content', 'users', ...)" - see http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_search/6 And access forbidden gone.
Once this is done, search will call your hook again (actually, there are quite a few calls, you can for example drupal_set_message($op) in your hook to see them all), and one of those calls will be with $op = "search" as well (coming from search_data() in search.module).

How to get previous page route in Symfony?

I am looking for way to do this in 'right' symfony way.
There's a way to get the referer page from the $request variable. For example, if I was in myaction/mypage and click to myaction2/mypage2 by this getReferer() method I get 'http://myweb/myaction/mypage'.
If you are in an action method this can be done by
public function executeMyaction(sfWebRequest $request)
{
$previousUrl = $request->getReferer();
...
}
if you are somewhere else you can get the request by getting the conext
$previousUrl = $this->getContext()->getRequest()->getReferer();
For for sfWebRequest methods check the sfWebRequest API.
Note: this value could be inaccesible using proxy's

Asp.net Routing - Route constraints and empty Route

I have a url that I want to map routing to:
http://siteurl.com/member/edit.aspx?tab=tabvalue
where tabvalue is one of: "personal", "professional", "values" or nothing.
I want to map it to a route like:
Member/Edit/{tab}
But my problem is - I don't know how to specify such constraints. I'm trying this regex:
^[personal|professional|values]{0,1}$
but it only works when I use url
http://siteurl.com/member/edit/personal
-or-
http://siteurl.com/member/edit/professional
and doesn't work for
http://siteurl.com/member/edit/
Any ideas how to specify the correct constraint?
P.S. I'm not using MVC, just asp.net WebForms
Thanks!
[ ] is for character set.
use ( ) instead
^(personal|professional|values){0,1}$
It's possible this doesn't quite meet your requirements, but if you build an enum such as this...
public enum TabValue
{
Personal,
Professional,
Values,
}
... and define your Action as ...
public ActionResult Edit(TabValue? tabvalue)
{
return View("Index");
}
... then the nullable value type of TabValue? will ensure that the following urls...
http://localhost/member/Edit?tabvalue=Professional
http://localhost/member/Edit?tabvalue=Personal
http://localhost/member/Edit?tabvalue=Values
... all supply a value for tabvalue (and the casing here isn't import), where as these urls..
http://localhost:51590/Home/Edit?tabvalue=Cheese
http://localhost:51590/Home/Edit
... hit your action with a tabvalue of null. No special routing is required to make this work.
try specifying a default value of UrlParameter.Optional in the route declaration for tab.
ps. it should work, but maybe you have to do the above explicitely
Try this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("",
"Member/Edit/{tab}",
"~/member/edit.aspx",
true,
new RouteValueDictionary
{{"tab", ""}},
new RouteValueDictionary
{{"tab", "^[personal|professional|values]{0,1}$"}}
);
}
I have used one framework before to do this. I am not sure if you want to use a framework or if you are using one already but check this out:
http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx
I have used it on a website, it is relatively easy to set up -- all rules are specified in the web.config file and you have certain freedom in designing your routes.
Hope it helps
Consider having 3 (or 4) routes. If the value of {tab} is not dynamic at runtime, having 3 static routes is cleaner than a regex. The regex is usually only useful when there are many values at runtime, such as matching a number, date, etc.

Resources