I have two controllers, homepage and Security.
In the homepage, I am displaying one view and in the security, I am doing some things, and one of them is the email address validation.
What I would like is that when the email validation code is not valid, display the homepage with a flash message. For that, I will have to render the indexAction of the HomepageController, from the Security controller, by giving him as parameter the flash message.
How can this be done? Can I render a route or an action from another controleller?
Thank you in advance.
I believe the checking should not be done in the Security controller. Right place in my opinion is a separate validator service or right in the entity which uses the email address.
But to your question, you can call another controller's action with $this->forward() method:
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
return $response;
}
The sample comes from symfony2 documentation on: http://symfony.com/doc/2.0/book/controller.html#forwarding
I have found the solution, simply use the forward function by specifying the controller and the action nanme:
return $this->forward('MerrinMainBundle:Homepage:Index', array('flash_message'=>$flash_message));
redirectToRoute : Just a recap with current symfony versions (as of 2016/11/25 with v2.3+)
public function genericAction(Request $request)
{
if ($this->evalSomething())
{
$request->getSession()->getFlashBag()
->add('warning', 'some.flash.message');
$response = $this->redirectToRoute('app_index', [
'flash_message' => $request->getSession()->getFlashBag(),
]);
} else {
//... other logic
}
return $response;
}
Related
How do I tell my API to display a particular result based on another column?
e.g. localhost:8000/api/gadgets/{{id}}
Normally it returns the particular information of the specific gadget with that ID and localhost:8000/api/gadgets/{{imei_code}} does not return any value or an error whereas imei_code is a column that I needed to pass as a GET request...
I'm using the normal resource controller
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response($response, 200);
}
Also I need help on how I can create like a search function in the controller.
You can`t do two similar URLs. I think your route for URL
localhost:8000/api/gadgets/{{imei_code}}
isn`t work. Also the order of the routes is important and route that defined firstly will be have higer priority then route that defined secondly.
Because your routes /api/gadgets/{{id}} and /api/gadgets/{{imei_code}} is similar in this case only the one described earlier will be processed.
You can define another router and handler, for example:
localhost:8000/api/gadgets
That will return a list of gadgets by default and you can add filters for imei_code. For example:
localhost:8000/api/gadgets?imei_code=123
And your handler for the new route may be writed something like that:
public function showList(Request $request): GadgetResource
{
if ($imeiCode = $request->query('imei_code')) {
$list = Gadget::query()->where('imei_code', $imeiCode)->get();
} else {
$list = Gadget::query()->take(10)->get();
}
return GadgetResource::collection($list);
}
Or like alternative solution you can create diferent route for searching of gadgets exactly by imei_code to get rid of any route conflicts
localhost:8000/api/gadgets/by_imei/123
public function findByImei(Request $request): GadgetResource
{
$imeiCode = $request->route('imei_code');
$item = Gadget::query()->where('imei_code', $imeiCode)->first();
return new GadgetResource($item);
}
You can specify the model key by scoping - check docs
Route::resource('gadgets', GadgetController::class)->scoped([
'gadget' => 'imei_code'
]);
Than, when Laravel try to bind Gadget model in Controller - model will will be searched by key imei_code.
This code equvalent of
Route::get('/gadget/{gadget:imei_code}');
Try to change response
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response()->json($response);
}
I'm using Laravel 5.5.
My objective is to redirect to another method on the same controller to display a view with data.
class SeancesController extends Controller {
...
public function getRecommandations(Request $request) {
...
$data = [
'recommandationAutresActiviteMemeDateHeure' => $recommandationAutresActiviteMemeDateHeure,
'recommandationsMemeActiviteMemeHeure' => $recommandationsMemeActiviteMemeHeure,
'recommandationsMemeActiviteMemeDate' => $recommandationsMemeActiviteMemeDate
];
return redirect()->action('SeancesController#showRecommandations', $data);
}
public function showRecommandations(Request $request) {
return view('listeRecommandations', $request->data);
}
}
It is the right way to do this? Because I get this error :
InvalidArgumentException: Action App\Http\Controllers\SeancesController#showRecommandations not defined. in file /home/nicolas/public_html/M1_CSI/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 338
I need to use action because I use an ajax call to access at getRecommandations().
I used this doc : http://laraveldaily.com/all-about-redirects-in-laravel-5/.
I didn't add a route that points to showRecommendations on my routing file. It's a problem?
Thank's for help!
I didn't add a route that points to showRecommendations on my routing file. It's a problem?
yes , it is a problem. because the redirector checks the routes that are assigned to the action and redirects the user to the route.
So, I have a page with a button on it with the value "Create". When I click that Create button, without filling out any of the fields, it validates the form and displays error messages on the same page. When I do that in the browser, it works fine, but when I do it with phpunit, it has unexpected results and I do not know why.
Here is my integration test:
public function testCreateValidation()
{
$this->visit(route('patients.indexes.create', $this->patient->id));
$this->press('Create');
$this->seePageIs(route('patients.indexes.create', $this->patient->id));
}
And this is the result:
There was 1 failure:
1) Tests\Integration\IndexControllerTest::testCreateValidation
Did not land on expected page [http://localhost/patients/69/indexes/create].
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/patients/69/indexes/create'
+'http://localhost/patients'
/vagrant/vendor/laravel/framework/src/Illuminate/Foundation/Testing/InteractsWithPages.php:141
/vagrant/tests/Integration/IndexControllerTest.php:51
I don't understand why it is being redirected to the patients page.
Here is the Laravel create method that is being tested:
public function create($id)
{
$index = $this->indexes->newInstance();
$patient = $this->patients->findOrFail($id);
return view('patient.index.create', ['index' => $index, 'patient' => $patient]);
}
And here is the relevant section of the create view:
<?= Form::open(['route' => array('patients.indexes.store', $patient->id), 'class' => 'form-horizontal']) ?>
#include('patient.index._form')
<?= Form::submit('Create', ['class' => 'btn btn-primary']) ?>
<?= Form::close() ?>
And finally the store method that it is being sent to:
public function store(IndexRequest $request, $id)
{
$index = $this->indexes->newInstance();
$index->fill($request->all());
$index->patient_id = $id;
$index->save();
$patient = $index->patient;
return redirect()->route('patients.edit', $patient);
}
I am also using a FormRequest to validate the input:
public function rules()
{
return [
'index_title' => 'required',
'index_description' => 'required',
];
}
So essentially, since it is failing the validation in the IndexRequest, the IndexRequest should kick it back to the patients.indexes.create view and display errors. But for some reason it's being kicked to the patients page (this ONLY happens in the test, if I try it out by manually clicking the Create button in the browser, it works as expected)
I've had this issue before but have never been able to solve it. Any ideas?
It sounds like you're having CSRF issues. When you navigate to the form in your browser, Laravel stores a special token in your browser's cookies and in the request headers. Then, when you submit the form it looks for that token to make sure you are the one submitting the form.
When you test with PHPUnit, that token isn't sent, so you either have to send it yourself, or you have to exclude your tests from the middleware that checks for the token. Excluding your tests is the easier method.
In Laravel 5.0 I did that by overriding the handle() method in the VerifyCsrfToken middleware.
class VerifyCsrfToken extends BaseVerifier {
// Override the handle() method in the BaseVerifier class
public function handle($request, Closure $next) {
// When the App environment is 'testing', skip CSRF validation.
if (app()->environment() === 'testing') {
return $next($request);
}
return parent::handle($request, $next);
}
}
By default, PHPUnit pulls the environment variables from the phpunit.xml file in your Laravel site root. The APP_ENV variable is the one that controls the application environment name, and it defaults to 'testing'. If yours is different, you then need to change the code I provided to match it.
If middleware is in fact the problem you can exclude it from the tests using the WithoutMiddleware trait:
class IndexControllerTest extends TestCase
{
use Illuminate\Foundation\Testing\WithoutMiddleware;
...
I'm trying to create a custom validation rule within laravel 4 and am struggling to get it to work or understand what I'm doing.
Currently - when I try to submit a form and validate it i get the following in my browser:
/**/
Which I'm taking as something is broken!
I have created a class in app/validators/customValidate.php
class CustomValidate extends Illuminate\Validation\Validator
{
public function uniqueMailchimp($attribute, $value, $parameters)
{
$mailchimp = MailchimpWrapper::lists()
->memberInfo(
'xxxxxxx',
array('emails'=>array(
'email'=>$value
)
));
//dd($$mailchimp['success_count']);
return ($mailchimp['success_count'] > 0 ? false : true );
}
I have run composer dump-autload
In my controller I am doing the following:
$rules = array(
'email' =>'email|uniqueMailchimp',
);
$messages = array(
'uniqueMailchimp'=>'The email provided has already been used.'
);
$validator = Validator::make($data, $rules, $messages);
}
I am then checking for a valid form with:
if($validator->passes()) {
# code
}
if validation fails the controller should redirect to the view:
return Redirect::route('members.create')
->withInput()
->withErrors($validator)
->with('errMessage', $message);
I've probably missed a step. I've seen posts about registering the rule in global.php but I'm not sure what I'm doing.
Any help appreciated
You are quite right - you need to register your rule with the validator. In any bootstrap-like file (a service provider is the best candidate if you have one, else app/start/global.php is good, and routes.php wouldn't be crazy either) you need the following code:
Validator::extend('foo', 'CustomValidate#uniqueMailchimp');
However, if you take a look at the docs you'll see that you don't need a whole class for this - you can just do it as a closure. A class is useful if you want the automatic IoC DI carried out for you though (although you don't appear to use that in your validator).
I am currently trying to create a link on the index page that'll allow users to create an item. My routes.php looks like
Route::controller('items', 'ItemController');
and my ItemController looks like
class ItemController extends BaseController
{
// create variable
protected $item;
// create constructor
public function __construct(Item $item)
{
$this->item = $item;
}
public function getIndex()
{
// return all the items
$items = $this->item->all();
return View::make('items.index', compact('items'));
}
public function getCreate()
{
return View::make('items.create');
}
public function postStore()
{
$input = Input::all();
// checks the input with the validator rules from the Item model
$v = Validator::make($input, Item::$rules);
if ($v->passes())
{
$this->items->create($input);
return Redirect::route('items.index');
}
return Redirect::route('items.create');
}
}
I have tried changing the getIndex() to just index() but then I get a controller method not found. So, that is why I am using getIndex().
I think I have set up my create controllers correctly but when I go to the items/create url I get a
Unable to generate a URL for the named route "items.store" as such route does not exist.
error. I have tried using just store() and getStore() instead of postStore() but I keep getting the same error.
Anybody know what the problem might be? I don't understand why the URL isn't being generated.
You are using Route::controller() which does generate route names as far as I know.
i.e. you are referring to "items.store" - that is a route name.
You should either;
Define all routes specifically (probably best - see this blog here)
Use Route::resource('items', 'ItemController'); see docs here
If you use Route::resource - then you'll need to change your controller names
The error tells you, that the route name is not defined:
Unable to generate a URL for the named route "items.store" as such route does not exist.
Have a look in the Laravel 4 Docs in the Named Routes section. There are several examples that'll make you clear how to use these kind of routes.
Also have a look at the RESTful Controllers section.
Here's an example for your question:
Route::get('items', array(
'as' => 'items.store',
'uses' => 'ItemController#getIndex',
));
As The Shift Exchange said, Route::controller() doesn't generate names, but you can do it using a third parameter:
Route::controller( 'items',
'ItemController',
[
'getIndex' => 'items.index',
'getCreate' => 'items.create',
'postStore' => 'items.store',
...
]
);