I have two forms on a page both submits the data via POST method. I want to handle both requests on the same url i.e /home and use different controllers and methods for both forms. Below are the two routes.
Route::post('home' ,'FacebookControllers\PostsController#save');
Route::post('home' , 'FacebookControllers\MessageController#storeMessage');
In PostsController#save I am checking
if(isset($_POST['submitPost']) && $_SERVER['REQUEST_METHOD']=='POST'){
//do something
}
and in MessageController#storeMessage I am doing the same for other form
if(isset($_POST['sendMessage']) && $_SERVER['REQUEST_METHOD']=='POST'){
return "got it";
}
The problem is that only second route works. I don't if I am doing right or wrong. Please lead me to the right direction.
Route::post('home' ,'FacebookControllers\PostsController#save');
Route::post('home' , 'FacebookControllers\MessageController#storeMessage');
won't work - how should laravel determine where to post to? The way I would go is to create two jobs and one route, then check for the value in Request and dispatch the correct job.
First, create two job classes with
php artisan make:job FacebookSave
php artisan make:job FacebookStoreMessage
The generated file will look much like this:
<?php
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Contracts\Bus\SelfHandling;
class FacebookSaveMessage extends Job implements SelfHandling
{
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//
}
}
In the job's handle() method you can do what you wanted to do in your Controller.
Now the route, let's do
Route::post('home' ,'FacebookControllers\PostsController#findAction');
and according to this in your PostsController, add a method (I called it findAction) like this:
public function findAction(\Illuminate\Http\Request $request) {
if ($request->has('submitPost')) {
return $this->dispatch(new \App\Jobs\FacebookSave($request));
} else if ($request->has('storeMessage')) {
return $this->dispatch(new \App\Jobs\FacebookStoreMessage($request));
}
return 'no action found';
}
This way the correct action will be performed depending on the submitted value.
Change the job's constructor to something like:
public function __construct($data)
{
$this->data = $data;
}
And you can access the submitted values from the forms you have submitted inside the job's handle() method with $this->data
If the purpose is only to maintain the URL that appears in the browser, you may apply a trick in which you submit your post request to different ROUTES that are specifically exist for processing purpose and then redirect back to the same URL.
For example:
Route::post('home' ,'FacebookControllers\PostsController#save');
Route::post('message' , 'FacebookControllers\MessageController#storeMessage');
Then in your view , you maybe have two diffrent forms in the same view:
<!-- the first form -->
<form action="{{url('home')}}" method="post">
Enter your post:
<input type="text" name="post" />
<button type="submit" >Save</button>
</form>
<!-- the second form -->
<form action="{{url('message')}}" method="post">
Enter your post:
<input type="text" name="post" />
<button type="submit" >Save</button>
</form>
Now in your controller, in the both actions do something like :
public function save(Request $request)
{
// do stuff
$obj->save()
return redirect('home')->with('status' , 'you have saved your post')
}
public function storeMessage(Request $request)
{
// do stuff
$obj->save()
return redirect('home')->with('status' , 'your message has been saved')
}
By doing so, the URL will remain same for the user, after the process is done the user will be redirected back to the same URL with the status.
May be this is not a good coding practice, but it solve the problem by maintaining the same URL while having multiple posts to the same controller in the same view.
The most important point here is that you have to strictly prevent an error during the process by using conditions and redirect to the same URL in case of any problem, otherwise the action will try to show the user the tricky ROUTE (yoursite.com/message) for any error.
Related
I wrote localisation helper in laravel which checks whether en, fr or another local is in the URI.
If no locale is supplied config("app.locale") should be prepended to the original URI and a redirect should be made to this new URI. I.e. /user should be redirected too /en/user.
I am currently trying to resolve this problem by using:
public function handle($request, Closure $next, $guard = null)
{
$langSegment = $request->segment(1);
// if first segment is language parameter then go on
if (strlen($langSegment) == 2 && ($langSegment == 'en' || $langSegment == 'fr')) {
App::setLocale($langSegment);
return $next($request);
} else {
$newURL=url(config("app.locale") . "/" . implode("/",$request->segments()));
return redirect($newURL);
}
}
This works fine for most request unless the method is POST and there is no $language set. When this is the case the user is redirect but the method is changed to a POST request.
I also tried changing my redirect to
return redirect()->route('routeName', $request->all(), 302, ['method','POST'])
But this also doesn't work.
So I did some testing with regards to the HTTP status code 307.
Let me first describe my test setup, I created the following routes:
Route::get("/help", 'HelpController#index');
Route::post("/post", 'HelpController#post');
Route::post("/redirected", 'HelpController#redirected');
The HelpController contained the following code:
<?php
namespace App\Http\Controllers;
class HelpController extends Controller
{
public function index(){
return view('help');
}
public function post(){
return redirect('/redirected', 307);
}
public function redirected(){
echo "Success";
}
}
and help.blade.php was a very basic form namely:
<form method="post" action="/post">
#csrf
<button>Go</button>
</form>
I am glad to report that a 307 return code does successfully keep the POST method.
I.e. when I went to the /help url and pressed the "Go" button I saw the "Success" message as expected.
What does this mean for me you might ask?
Well we can solve your problems with a very simple change:
return redirect($newURL);
becomes
return redirect($newURL, 307);
Wasn't that easy in the end?
Furthermore as you can see in my test setup this also keeps the crsf protection which is a definite plus from a security standpoint.
I have a form in a tpl file:
<form action="{$link->getModuleLink('virtual_pos', 'validation', [], true)|escape:'html'}" method="post">
...
</form>
On submit I would like to get all the variables from the form and pass them to the controller 'validation'.
I don't wanna use any JS. It is a payment module for a store.
How can I do this?
I have found a solution in another thread.
When the link to the controller is created you can fill the variables that you need in the empty array parameter:
<form action="{$link->getModuleLink('virtual_pos', 'validation', ['id'=>$cart_id], true)|escape:'html'}" method="post">
Then in the controller you can get the data with the super global
$id_from_form_submit = $GET['id'];
If you know any other option please let me know.
In your module create a file controllers/front/validation.php.
There you need a class:
class virtual_posValidationModuleFrontController extends ModuleFrontController
{
public function postProcess()
{
/* where you get the values and validate the order */
}
public function initContent()
{
parent::initContent();
/* where you set data for a last page order confirmation */
}
}
Have you created this already?
I have a small form, where user's can Subscribe to my newsletter.
How can i pass the email address from my Layout to my Controller?
My Layout name is Footer.phtml, here's the code:
<div id="subscribe">
<form name="newsletterRegister" method="post" action="">
<span>Subscribe to the Newsletter</span>
<input class="subscribeNewsletter" name="email" type="text">
<input id="subscribe_ok" type="image" src="/www/assets/newImages/footer/Ok.png" value="">
</form>
</div>
I have a controller called NewsletterController.php
I'm kinda lost with Zend Framework, can anyone help me figuring out what i have to do??
Well change this
<form name="newsletterRegister" method="post" action="">
To this
<form name="newsletterRegister" method="post" action="NewsletterController/YOURACTION">
And in your controller just get the data like this
$request = $this->getRequest();
$request->getPost()
If the action of your form is empty, it will post to itself.
But maybe you dont want to check on every page if the newsletter is send.
Try using a Controller Plugin, check the request object for the input field, name it unique like email_newsletter, if is not empty, do your logic.
File: application/plugins/Newsletter.php
class Application_Plugin_Newsletter extends Zend_Controller_Plugin_Abstract {
//before dispatching starts
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$email = $request->getParam('email_newsletter',NULL);
if(!is_null($mail)) {
//check if is valid
if(Zend_Validate::is($email,'')) {
//do your logic
}
else {
//set some error messages
//maybe use helper flashMessenger
}
}
}
}
File: Bootrap.php
protected function _initPlugins() {
$this->bootstrap('frontController');
//Get FrontController Instance
$frontController = $this->getResource('frontController');
$frontController->registerPlugin(new Application_Plugin_Newsletter());
return $frontController;
}
OR
Set a form action like '/newsletter/subscribe'.
Then in controller 'newsletter' action 'subscribe' check the form and redirect to the sending page.
Maybe you should store sth like a last page visited to the session, or add a hidden input to that newsletter form, representing the current page you want to redirect to after the newsletter subscription is done.
How can I have multiple actions in my layout from different controllers/modules?
I tried this:
<div id="login"><?php $x=new User_LoginController; $x->LoginAction() ?>
<div id="news"><?php $x=new Site_NewsController; $x->ShowAction() ?>
You'll want to implement view helpers, specifically the placeholder() view helper.
For example to render a login form in any or all pages of your application, we start with a placholder for the form in our layout or view script:
<!--layout.phtml-->
<div>
<?php echo $this->layout()->login . "\n"?>
</div>
I use an action helper to prepare the form for display:
<?php
/**
* Prepares login form for display
*/
class My_Controller_Action_Helper_Login extends Zend_Controller_Action_Helper_Abstract
{
/**
* #return \Application_Form_Login
*/
public function direct()
{
$form = new Application_Form_Login();
//this is the url of the action this form will default too
$form->setAction('/index/login');
return $form;
}
}
now from any controller or front controller plugin the placeholder can be setup:
public function preDispatch()
{
$this->_helper->layout()->login = $this->_helper->login();
}
now the login form will display in any action from this controller that uses layout.phtml as it's layout. I'll let you discover plugins yourself.
Using helpers with placeholders would usually be the prefered way to accomplish what you want. However if you absolutely must display an action inside of anothers view you can use the Action view helper, just be aware that performance may suffer.
<div id="login">
<?php echo $this->action('login', 'login', 'user'); ?>
</div>
I didn't get what exactly you want?
What I guessed is may be you want to call this function(action) from layout to show what is
returning from there into layout......
I am creating a custom MVC style framework from scratch and am at the point where I need to implement the code to control what happens on POST.
At the moment I have a main index.php which acts as a controller and passes data to other controllers such as:
profilecontroller.class.php
forumcontroller.class.php
At the moment I see two options as to where the POST controllers can go ..
First Approach
Firstly for site wide posts such as login that can occur on any page I would use something like this in the very first index.php to redirect all POST to a specific POST controller that then sends the data to a model to be processed:
if($_POST)
//post controller, works on specific form id's
Alternate Approach
The other option I see would be to build the POST identifier into the model construction sections but I don't think this would be very manageable/wise as they'd always be checked and resulting in more loaded code?
Are there any good/simple examples out there?
I'm creating my mvc to be as light as possible so that's my reason for going from scratch.
In a RESTful setup, you would normally have a controller for an object, say news, and then actions such as add, edit, delete etc.
Within your actions, you should then assert what HTTP method should be used to access the method, if one should be. For example:
<?php
class NewsController extends AbstractController {
public function save() {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
header('HTTP/1.1 405 Method Not Allowed');
die('Please use POST.');
}
// carry on knowing we're working with a POST request
}
}
Creating a separate controller for POST requests would, as you say, quickly becoming unruly and unmanageable.
If you're looking for a way of handling requests for different HTTP methods within different controller actions, then maybe check out ToroPHP. It's a lightweight (single file) router, where you map a request to a class that's referred to as a handler, and then that handler has methods for different HTTP methods. A quick example:
<?php
require 'lib/torophp/toro.php';
require 'classes/handlers/HomeHandler.php';
$toro = new ToroApplication(array(
array('/', 'HomeHandler')
));
$toro->serve();
And then your HomeHandler would look as follows:
<?php
class HomeHandler {
public function get() {
echo 'Hello, world!';
}
public function post() {
echo 'Try performing a GET request for the home page, buddy.';
}
// and so on...
}
Hope that helps.
This is my default Controller :
<?php
Class Controller_Home{
public $Registery = null;
final public function __construct($Registery){ $this->Registery = $Registery; }
final public function Init($Method=null){
# Quelle action on fait ?
if($Method){
$Split = explode('_', $Method);
$MethodName = 'Action';
foreach($Split as $Splitted){
$MethodName.= '_'.ucfirst($Splitted);
}
if(method_exists($this, $MethodName)){
$this->$MethodName();
} else {
echo '404';
die;
}
} else {
$this->Action_Default();
}
}
final public function Action_Default(){
$this->Registery->Import('Library.Account');
var_dump($this->Registery->Account);
echo 'Default Home';
}
}
As you can see, once you are in Action_Default, you can do whatever you want based on $_GET, $_POST, whatever you want ...
So with this code :
website.com/home/bob/ will use function Action_Bob inside the controller Home (Home::Action_Bob) ... if you see $_POST just put inside Action_Bob this
public function Action_Bob(){
if($_POST){
$this->Action_Bob_Post();
}
// continue
}