Controller method not called in laravel 4 - laravel

I'm trying to learn laravel 4. I created a form(using view) and returned it via a controller(testController) using index method. I had created this controller using artisan command.
i created another method (dologin) in the controller which would process the form. In the form url parameter i gave the address of dologin method.
This is the route:
Route::resource('test', 'testController');
This is the controller
<?php
class testController extends \BaseController {
public function index()
{
return View::make('test.index');
}
public function dologin(){
echo "working";
}
and this is the index view file
{{ Form::open(array('url'=>'test/loginform')) }}
{{ Form::text('username', null, array('placeholder'=>'Username')) }}<br/>
{{ Form::password('password', array('placeholder'=>'Password')) }}<br/>
{{ Form::submit('Login') }}
{{ Form::close() }}
After submitting form, it should echo "working" in the browser. But after submitting the form, page is blank. The url changes though from
/laravel/public/index.php/test/
to
/laravel/public/index.php/test/loginform

umefarooq's answer is correct, however hopefully this answer should give you a bit more insight into getting a head-start in your Laravel development as well as a consistent best-practice programming style.
Firstly, class names should really start with a capital letter. Try to keep methods / function names starting with a lower case letter, and class names starting with a capital.
Secondly, you don't need the \ in front of BaseController. You only need the backslash if you are name-spacing your controller. e.g. if your controller is in the folder Admin\TestController.php, and you put your TestController in the Admin namespace by typing <?php namespace Admin at the beginning of the file. This is when you should use \BaseController because you are telling your TestController to extend BaseController from the Global Namespace. Alternatively, before you declare your class, you can type use BaseController; and you don't need to put a \ in every time.
Specifically related to your question:
When you use resource routes in your routes file, you are telling Laravel that the controller can have any or all of the following methods: index, show, create, store, edit, update and destroy.
As such, Route::resource('test', 'TestController'); will point to TestController.php inside your controllers folder.
Your TestController should be structured as follows, most restful controllers will use the below as some kind of boilerplate:
<?php
class TestController extends BaseController
{
public function __construct()
{
}
// Typically used for listing all or filtered subset of items
public function index()
{
$tests = Test::all();
return View::make('test.index', compact('tests'));
}
// Typically shows a specific item detail
public function show($id)
{
$test = Test::find($id);
return View::make('test.show', compact('test'));
}
// Typically used to show the form which creates a new resource.
public function create()
{
return View::make('test.create');
}
// Handles the post request from the create form
public function store()
{
$test = new Test;
$test->attribute1 = Input::get('attribute1');
$test->attribute2 = Input::get('attribute2');
$test->attribute3 = Input::get('attribute3');
$test->attribute4 = Input::get('attribute4');
if ($test->save())
{
return Redirect::route('test.show', $test->id);
}
}
// Shows the edit form
public function edit($id)
{
$test = Test::find($id);
return View::make('test.edit', compact('test'));
}
// Handles storing the submitted PUT request from the edit form.
public function update($id)
{
$test = Test::find($id);
$test->attribute1 = Input::get('attribute1');
$test->attribute2 = Input::get('attribute2');
$test->attribute3 = Input::get('attribute3');
$test->attribute4 = Input::get('attribute4');
if ($test->save())
{
return Redirect::route('test.show', [$id]);
}
}
// Used to delete a resource.
public function destroy($id)
{
$test = Test::find($id);
$test->delete();
return Redirect::route('test.index');
}
}
Also, the beauty of using Resource Controllers is that you can take advantage of named routes.
in the terminal window, type in php artisan routes.
You should see 7 named routes.
test.index
test.destroy
test.show
test.edit
test.destroy
test.create
test.update
So within your form, instead of doing
{{ Form::open(array('url'=>'test/loginform')) }} you can point the url to a named route instead:
{{ Form::open(array('route' => array('test.store')) }}
That way if you ever change the url, or need to move around your site structure, this will be easy, because the forms post url will auto bind to the named route within the routes file. You wont need to update every single one of your views to ensure that the url's are pointing to the correct location.
Finally, as a starting point, I would recommend using JefreyWay/Laravel-4-Generators package. https://github.com/JeffreyWay/Laravel-4-Generators . Use them to create your resources, controllers, views etc. and see how the generators scaffold your models, views and, controllers for you.
Here is another resource to help you get started:
https://laracasts.com/lessons/understanding-rest

Route::resource('test', 'testController');
will work for RESTful method of controller, like index, edit, destroy, create and now you are using custom method of controller for this you need to create another route
Route::post("test/loginform",'testController#dologin');
hope this will work for you. read route documentation http://laravel.com/docs/routing

In addition to what umefarooq said, which is 100% accurate. You need to look into flash messages as well.
public function dologin(){
//do login verification stuff
If login validated
Return redirect::to(logged/page)->with('message', 'You're logged in');
If login failed
Return redirect::to('test')->with('message', 'You login credentials fail');
}
For further research:
http://laravel.com/docs/responses

Related

Laravel Route Model Binding Reusability

I'm creating a like feature for my application where users can like posts, events, products etc.
I have a LikeController and a Trait which handles the like functionality
public function store(Post $post)
{
$post->like();
return back();
}
The code above is to like a post
I don't want to duplicate code and create separate functions to perfrom the same exact thing on events or products and I was wondering how to perform route model binding and get the application to just execute the one function, passing model information depending on what is being liked post, event or product.
The following code works fine but does not implement the DRY principle
public function store(Post $post)
{
$post->like();
return back();
}
public function store_event(Event $event)
{
$event->like();
return back();
}
The followinf is the trait
trait LikeTrait
{
public function getLikesCountAtrribute()
{
return $this->likes->count();
}
public function like()
{
if (!$this->likes()->where(['user_id' => auth()->id()])->exists()) {
$this->likes()->create(['user_id' => auth()->id()]);
}
}
public function likes()
{
return $this->morphMany(Like::class, 'likeable');
}
public function isLiked()
{
return !!$this->likes->where('user_id', auth()->id())->count();
}
}
My web routes file is as follows
Route::post('post/{post}/likes', 'LikeController#store');
Route::post('event/{event}/likes', 'LikeController#store_event');
So the outcome I want is to call the same method and pass the relevant model.
Thanks in advance
You can have a specific route for such actions, may it be 'actions':
Route::post('actions/like','ActionsController#like')->name('actions.like');
Then in the request you send the object you wish to perform the action on, i personal have it hashed, the hash contains the ID and the class_name (object type) in an stdClass.
That's how i personally do it:
Every Model i have inherits Base Model, which contains hash attribute, which contains
$hash = new stdClass;
$hash->id = $this->id;
$hash->type = get_class($this);
return encrypt($hash);
This will return a string value of what's there, and encrypted, you can have a password for that as well.
Then you let's say you have the like button inside a form or javascript you can do that:
<form action="{{ route('actions.like') }} method="post">
<input type="hidden" name="item" value="{{ $thisViewItem->hash }}">
<button type="submit">Like</button>
</form>
Doing so, when liking an object you send the hashed string as the data, thus getting a request of $request->get('item') containing the object (id and type). then process it in the controller however you like.
If you're sending this through javascript you may want to urlencode that.
then in ActionsController#like you can have something like that:
$item = decrypt($request->get('item'));
# Will result in:
# Item->id = 1;
# Item->type = 'App\Post';
$Type = $Item->type;
# Build the model from variable
# Get the model by $item->id
$Model = (new $Type)->find($item->id);
# Like the model
$Like = $Model->like();
// the rest...
I personally prefer to combine and encrypt the id+type in a string, but you can send the id and type in plain text and have a route named like so:
Route::post('actions/like/{type}/{id}','ActionsController#like');
Then build the model from the Type+ID followed by what you have in trait ($Model->like());
It's all up to you, but i'm trying to hint that if you want to reuse the like action in many places, you may want to start building the logic starting from the action itself(likes, comments) not from the target (posts, events).
The codes i placed in here are written in here and not pasted from what i actually do, I'm trying to get you the concept. You can write it however you prefer.
I don't know whether this is gonna work, but please have a go.
You could try explicit binding. Lets define explicit bindings in the App\Providers\RouteServiceProvider:
public function boot()
{
parent::boot();
Route::model('post', App\Post::class);
Route::model('event', App\Event::class);
}
Then defining the routes:
Route::post('/posts/{post}/likes', 'LikesController#store');
Route::post('/events/{event}/likes', 'LikesController#store');
Finally in the controller:
class LikesController extends Controller
{
public function store($object)
{
$object->like();
}
}

Returning same variable to every controller in laravel

I need to send the same result to almost every view page, so I need to bind the variables and return with every controller.
My sample code
public function index()
{
$drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
$locations = Location::get();
return view('visitor.index', compact('drcategory','locations'));
}
public function contact()
{
$drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
$locations = Location::get();
return view('visitor.contact', compact('drcategory','locations'));
}
But as you see, I need to write same code over and over again. How can I write it once and include it any function whenever I need?
I thought about using a constructor, but I cannot figure out how I can implement this.
You are able to achieve this by using the View::share() function within the AppServicerProvider:
App\Providers\AppServiceProvider.php:
public function __construct()
{
use View::Share('variableName', $variableValue );
}
Then, within your controller, you call your view as normal:
public function myTestAction()
{
return view('view.name.here');
}
Now you can call your variable within the view:
<p>{{ variableName }}</p>
You can read more in the docs.
There are a few ways to implement this.
You can go with a service, a provider or, like you said, within the constructor.
I am guessing you will share this between more parts of your code, not just this controller and for such, I would do a service with static calls if the code is that short and focused.
If you are absolutely sure it is only a special case for this controller then you can do:
class YourController
{
protected $drcategory;
public function __construct()
{
$this->drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
}
// Your other functions here
}
In the end, I would still put your query under a Service or Provider and pass that to the controller instead of having it directly there. Maybe something extra to explore? :)
For this, you can use View Composer Binding feature of laravel
add this is in boot function of AppServiceProvider
View::composer('*', function ($view) {
$view->with('drcategory', DoctorCategory::orderBy('speciality', 'asc')->get());
$view->with('locations', Location::get());
}); //please import class...
when you visit on every page you can access drcategory and location object every time
and no need to send drcategory and location form every controller to view.
Edit your controller method
public function index()
{
return view('visitor.index');
}
#Sunil mentioned way View Composer Binding is the best way to achieve this.

How do I send data to partial views from controller in laravel?

I have setup my navigation menu from a ViewComposer (see laravel view composers: https://laravel.com/docs/5.6/views#view-composers) like this
View::composer('partials.nav', function ($view) {
$view->with('menu', Nav::all());
});
What I need is that from some controllers to setup which navigation item is active, ie "current section".
Question:
How do I send from some controllers a variable to "partials.nav" like currentNavItem?
Do I send it with the rest of the variables for returned view?
like
return view('page.blade.php",$viewVariables + $optionalVariablesForPartialsViews);
It looks spammy
Side notes:
I use laravel 5.6
Later edit
It looks Laravel 5.1 : Passing Data to View Composer might be an options. I will try and get back .
Because the $variable you want to send differs in different controller's actions yes you need to specify the $variable
return view('page.blade.php",$viewVariables,$variablesForPartialsViews);
of course you might need to set a default value for the $variable in order to avoid undefined variable error
You should handle the parameters.
for exemple:
public function compose(View $view)
{
$view->with('page', $this->getPage());
}
public function getPage()
{
$viewVariables = 2;
$optionalVariablesForPartialsViews = 1;
return $viewVariables + $optionalVariablesForPartialsViews;
}
Under your app folder make a class named yourClassNameFacade. Your class would look like this.
class yourClassNameFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'keyNameYouDecide';
}
}
Then go to the file app/Providers/AppServiceProvider.php and add to the register function
public function register()
{
$this->app->bind('keyNameYouDecide', function (){
//below your logic, in my case a call to the eloquent database model to retrieve all items.
//but you can return whatever you want and its available in your whole application.
return \App\MyEloquentClassName::all();
});
}
Then in your view or any other place you want it in your application you do this to reference it.
view is the following code:
{{ resolve('keyNameYouDecide') }}
if you want to check what is in it do this:
{{ ddd(resolve('keyNameYouDecide')) }}
anywhere else in your code you can just do:
resolve('keyNameYouDecide'))

Laravel - Use Class like Auth

I have a Class Post. Created the Model, Restfull Resource Controller.
Now i implemented the show function in my Resource Controller.
So if someone routes to /post/234234 he will automatically see the post.
But now I want to create a new static function on myself. Let's call it myFunction(). I don't like to hand over the id all the time. Isn't there a possibilty to create a object or something like that, so I can use this like that Post::myFunction(), without hand over the id all the time.
It's similar to the Auth Class. I mean I can check if the user is logged in just like that Auth::check().
Update
Let's describe it more clearly. This is my PostController#show:
public function show($id)
{
//Get board information
$post = Post::find($id);
//Return view
return view('post')->with(array(
'posts' => $post
));
}
It shows just the post. In my view I have a button called Follow up. I only want to show it, if he didn't follow up the post yet. Now i thought about to edit the Model Post.php and add a static function followed() so i can just do this in the view:
#if(Post::followed())
<button>Follow up</button>
#endif
Yes. You can simply create a static function:
public static function myFunction(){
}
Just note that this function will be called in static context so you there's no $this available.
Alternatively you can create a Facade (Auth is a Facade). The process is described pretty well in the documentation about facades
As for your specific case I don't even think a static method is needed. Since you pass $post to the view you can just add a regular public method:
public function isFollowing(){
}
And then do this in your view:
#if(!$post->isFollowing())
<button>Follow up</button>
#endif

How do I access a global model instance in laravel 4?

In Laravel 4, how do I create an instance of a model and make it globally available? Even in views. I'm looking to do something similar to the way you get the User instance using Auth::User->name (the syntax I mean, not storing in a session) but in this case it would be ModelName::DefaultEntity->attribute.
A little more detail...
I am writing an application that will house multiple websites - a bit like a CMS. So I have a Website model. Each Website model will have a URL attribute so that when a user visits the URL the application can retrieve the Website model from the database and brand the website appropriately e.g. Title, logo, theme, etc...
I would like the current Website model to be available everywhere without having to create a new instance of Website in every controller/method. So in my layouts and views I could just say something like:
{{ Website::Website()->name }}
or
{{ CurrentWebsite::name }}
I have achieved the first one by making a static method in the Website model:
public static function current()
{
return Website::find(1); // just to test it for now
}
But with that, it will have to do a database query every time I say:
{{ Website::current()->name }}
Plus it doesn't feel right.
Can anyone help?
Kind regards,
Robin
You probably are looking for 'a shared container bind'. See the docs here.
<?php
App::singleton('foo', function()
{
return Website::whereCode('whoop')->first();
});
App::make('foo'); // every where you need it
Create normal class. Like CurrentWebsite or Website or whatever.
class Website {
public function a() {
//your code
}
}
Create facade (WebsiteFacade.php)
use Illuminate\Support\Facades\Facade;
class WebsiteFacade extends Facade {
protected static function getFacadeAccessor() { return 'website'; }
}
Create Service Provider
use Illuminate\Support\ServiceProvider;
class WebsiteServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('website', function()
{
return new Website();
});
}
}
4.Go to your config/app.php and add folowing:
'providers' => array(
'WebsiteServiceProvider'
)
and
'aliases' => array(
'WebsiteFacade'
)
5.Refrech auto loader. And Now you can access Website class anywhere like this:
Website::a();
What you already have is good, but if you just want prevent that query from executing every time, you can cache it:
public static function current()
{
return Website::remember(10)->find(1); // just to test it for now
}
Adding a listener to your routes.php:
DB::listen(function($sql, $bindings, $time) { var_dump($sql); var_dump($bindings); });
And executing it:
{{ Website::current()->name }}
Will show the query in the first execution but not in the second, because it's cached.

Resources