I'm using Laminas framework (laminas/mvc v3.1) / Zend3. In certain cases I need to call a different action than prescribed for a given route, i.e. display a default page to users who are not authorised to view restricted content.
To do this, I've tweaked the onDispatch method in Module.php as follows:
public function onDispatch(MvcEvent $event) {
// check if content is restricted to the current user
if (content-is-restricted) {
$event->getRouteMatch()->setParam("controller", "{namespace}\Controller\{anotherController}");
$event->getRouteMatch()->setParam("action", "{defaultAction}");
$event->getRouteMatch()->setMatchedRouteName("{defaultRoute}");
}
else {
proceed-as-normal-to-the-action-prescribed-by-route
}
}
Unfortunately, the snippet above renders the following error:
A 404 error occurred
Page not found.
The requested controller was unable to dispatch the request.
Controller:
{namespace}\Controller\{anotherController}
No Exception available
This works though if the action is within the same controller but not if it's in a different one. What am I missing?
Note, I don't want to redirect the user and change the URL - just substitute what is showed to them
Related
In the Struts documentation, it says:
Another common workflow stategy is to first render a page using an alternate method, like input and then have it submit back to the default execute method.
https://struts.apache.org/core-developers/action-configuration.html#post-back-default
How to do it using annotation only? It seems that only the execute() method is called.
In the documentation it's said to render a page can be used an alternate method like input. This means that when you submit a form on the page it can return back with the input result. Usually it happens automatically during validation process if the validation fails or it hasErrors. Then you can submit the form back to the default action's execute method. You don't need to specify a method in the action configuration. Also if you didn't specify the action attribute in the form tag then the same action will execute which was used to render a page.
Configuring actions you can use the same page for success result when rendering a page using GET method and input when POST method is requested.
To use annotations to configure actions mapping you can use a Convention Plugin.
Also note, to map a class method to the action you should put #Action annotation directly on this method rather than on the class.
More detailed explanation and documentation you can find here.
#Namespace("/")
public class ProductAction extends ActionSupport {
public String execute() {
return SUCCESS;
}
#Action(value="product",
results=#Result(location="/product-list.jsp")
)
public String search() {
return SUCCESS;
}
}
Notice, that the method execute is not mapped, so it will not execute. If you need that method execute you should create mapping to it. For this purpose you could place annotation on class or on method execute.
Im trying to style my login page. My login url is website/Security/login. Im trying to locate the 'login' piece of the url. What have i done wrong below?
public function DisplayPageType() {
$param = $this->request->param('Action');
if ($param === 'login')
{
return 'Login';
}
Thanks
I think that won't work since the controller during render is the Page_Controller and not the Security controller. So the $Action param is not equal to login. It could be index, I'm not sure.
If you just want to check if you're in the login page, you can add this to your Page_Controller:
public function getIsLoginPage()
{
return $_REQUEST['url'] == '/Security/login';
}
Then in your template:
<body class="<%if $IsLoginPage %>login-page<% end_if %>">
A bit dirty but it's the quickest way I know.
Another way is to leverage SilverStripe's legacy support. You can add a css file called tabs.css at mysite/css/tabs.css. If this file exists, SilverStripe will include this in the page.
You can also create templates that SilverStripe will automatically use if they exist:
themes/<theme_name>/Security.ss - If you want your login page to use an entirely different layout.
themes/<theme_name>/Layout/Security_login.ss - If you want to change just the content part (the $Layout section)
I hope this helps.
#gpbnz is right, the $Action param is not equal to login, it actually returns null as accessing $this->request from the Page_Controller when accessing the Security/login returns a NullHTTPRequest.
To get the action, you will want to get the current controller using Controller::curr(). It is then as simple as calling getAction on this controller.
To confirm that the action isn't from a random controller that happens to have an action called login, you can check the instanceof the controller like so: Controller::curr() instanceof Security
This check will still allow it to work for any controller that extends Security though which may/may not happen depending on the project.
I would stick away from actually reading the URL for the information manually though as that can create issues with maintainability in the future.
To bring this to a nice little function:
public function isLoginPage()
{
$controller = Controller::curr();
return $controller instanceof Security && $controller->getAction() == 'login';
}
Otherwise #gpbnz had a good suggestion of using the template system to your advantage for overriding not only the styles but the HTML around it.
I use dektrium user registration form.
registration link generates domain.com/user/register link
but it's not base user model, this module is located inside vendor/dektrium folder.
Now in base controllers folder I have UsersController with view action.
and after finishing registration I want to start view action of UsersController to view users page.
This is registration module code
public function actionRegister()
{
if (!$this->module->enableRegistration) {
throw new NotFoundHttpException;
}
$model = $this->module->manager->createRegistrationForm();
if ($model->load(\Yii::$app->request->post()) && $model->register()) {
return $this->redirect(array('users/'.$model->username));
}
return $this->render('register', [
'model' => $model
]);
}
As you can see I've put there this code
return $this->redirect(array('users/'.$model->username));
Which is supposed to take user to it's own page at domain.com/users/username.
But unfortunatelly url is forming in the following way
domain.com/user/users/username
How can I fix this problem and direct user to domain.com/users/username page ?
Add an extra / in front of the users redirect. it should be
return $this->redirect(array('/users/'.$model->username));
Or you should actually create the url the proper way, that would be the best way to do this, but I do not know the way you have your rules set up so I cannot help you there. I am just guessing here but it should be:
return $this->redirect(array('users/view, 'username' => $model->username));
In this way you are using your url manager, not just hardcoding the url. In the future if you decide to change the link it will be much easier (replace just the url line in your config) and not go in files to change it.
Hi I have a resource controller in Laravel 4. It has all the default methods generated by artisan's controller:make.
Models etc are in place.
User clicks on a link in a view that does a URL::route to a named route pointing at a controller action. It points to the 'store()' method in the controller, which is meant to be a POST method.
I write my code in the 'store()' method to handle this request. It uses eloquent to insert data into db. It returns a plain text response with HTTP code 200.
When user clicks on the above mentioned link (that points to the store() method), it seems the browser simply jumps to the index (GET) of that controller and the code doesn't run because the store() method is bypassed.
When I move all code from within the store() method into the index() method, everything works as expected.
What am I doing wrong here that my 'store()' method is not handling my code. Even when creating URL to the store action directly using URL::action, this fails.
Can someone please enlighten me?
Code:
Store method:
public function store()
{
$itemsArray = Session::get('sdata');
$cartItem = new Cart;
$cartItem->session_id = Session::get('sid');
$cartItem->items = json_encode($itemsArray);
$cartItem->save();
return Response::make('an item was added to carts', 200);
}
View:
Go
Same result for this view also:
`Go`
This is because <a> tag, is able to send only GET request. Try to create a new method, for example addToCart, and then set new rout on routes.php
I want to redirect the user back to the path from which he started the request.
Example:
/profile
/profile/edit
/profile
OR:
/products
/profile/edit
/products
What do I have to set for this redirection mode?
Inside your controller for /profile/edit you can capture the page they came from with $request->headers->get('referer').
If /profile/edit is a page with a single form, I'd probably just add a hidden field that says where the redirect should go.
public function editAction(Request $request)
{
// If you have a POST value coming from the user, it will be used, otherwise
// assume this is the first time they landed on the page and grab the current
// referer. With this method it doesn't matter how many times they submit the form
// you won't accidentally overwrite the referer URL with /profile/edit. That could
// lead to a confusing loop.
$referer = $request->request->get('referer', $request->headers->get('referer'));
if ($formIsSaved)
{
return new RedirectResponse($referer)
}
return array(
// Your template should include a hidden field in the form that returns this.
'referer' => $referer,
);
}
You could pass a redirect path as a GET parameter — say, redirectTo — to the edit page and after the edit process is complete, redirect to that path.
return new RedirectResponse($request->query->get('redirectTo');
You could make it more robust by checking whether or not that parameter is provided, and if it isn't, redirect to some sort of a default path.