Laravel routes for RESTful controllers - php

Having the following controller:
class Admin_Images_Controller extends Admin_Controller
{
public $restful = true;
public function __construct()
{
parent::__construct();
}
public function get_index($id)
{
echo $id;
}
I don't understand why when I access it with no parameter for ID it works, as I get an error says missing parameter for ... but when I actually try to pass a parameters at http://site/admin/images/12 I get a 404 error. What am I missing?
I tried setting the following in my routes, no success either:
Route::any('admin/images', array(
'as' => 'admin_images',
'uses' => 'admin.images#index',
));
//or
Route::any('admin/images/(:any)', array(
'as' => 'admin_images',
'uses' => 'admin.images#index',
));
It seams that my issues with wildcards, 90% happen in my test linux envirnonment (ubuntu). Here's my routes.php that I'm currently using http://pastebin.com/f86A3Usx

it could be that you're using the same alias (admin_images) and also, check your order - put the more specific ones first, and more generic as you go down, like so:
Route::any('admin/images/(:any?)', array('uses' => 'admin.images#index'));
Have removed the alias, just for readability.

Route::get('admin/images/(:any)', 'admin.images#index');

You should make the $id parameter optional, by passing a default value (like null/false/1)
public function get_index($id = null)
{
if($id){
echo $id;
}else{
echo "No ID given!";
}
}
And use (:any?) in your route.

Updated Routes:
Route::any('admin/images/(:any?)', array(
'as' => 'admin_images',
'uses' => 'admin.images#index',
));
You can simplify your routing by combining your routes for each endpoint. By adding the "?" into your first parameter, this mean that anything can be present, but doesn't have to be. So both /admin/images and /admin/images/1234 are covered.
Updated Controller:
class Admin_Images_Controller extends Admin_Controller
{
public $restful = true;
public function __construct()
{
parent::__construct();
}
public function get_index($id=null)
{
echo $id;
}
// ...
}
With the addition of "= null" into your method parameter, you can now handle both routes into this function. A simple check of "equals null" within your method should put you well on your way to covering each senario.

Related

Laravel: How does Controller access parameters from Route?

I am very obviously a noob to Laravel and hope that someone can help me out.
The about screen is accessed through the route
Route::get('/about', array('as' => 'about', function()
{
return View::make('about')->with('title','About Screen')->with('class','about');
}));
The variables $title and $class are accessible in about.blade.php by {{ $title }} and {{ $class }}. If instead, I have a Controller in between,
Route::get('hello/create', array('as' => 'create', 'uses' =>
'HelloController#create', function()
{
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}));
How do I access $title and $class in the HelloController.php code (so that I can propagate the values to the coming View)?
P.S. I do know about the /hello/create/{name of variable} which is the answer on nearly all questions similar to this, but don't know how to use it to transmit variables NOT keyed onto the Http Request.
$title and $class are the values you are manually giving to the blade. These aren't the values that you are receiving in GET parameters in your route. So, you would do it the same way as you did in the closure.
Your route:
Route::get('hello/create', array('as' => 'create', 'uses' => 'HelloController#create'));
Controller method:
class HelloController{
public function create(){
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}
}
UPDATE:
From what I understood, you can also call controller's method inside the route's closure and pass parameters to the controller and call the view with these values inside the controller's method.
Your route file:
use App\Http\Controllers\HelloController;
Route::get('hello/create',function(){
$hello_obj = new HelloController();
return $hello_obj->create('create','hello.create');
});
Controller method:
class HelloController{
public function create($title,$class){
return View::make('hello/create')->with('title',$title)->with('class',$class);
}
}
First you need to clear your flow. You are -at the moment- manually setting the variables to be returnet to the view, so your route should look like this:
Route::get('hello/create', 'HelloController#create');
Then, your controller handles the logic:
public function create(Request $request)
{
return view('hello.create')->with('title','Create')->with('class','hello.create');
}
Now, if you need to send parameters from your frontend to your controller, you have two options:
Define route parameters.
Use query params.
Option 1
For the first option, you'll need to define your required/optional parameters in the route itselft:
Route::get('hello/create/{a_variable}', 'HelloController#create');
Then you access this parameter in any of this ways:
public function create(Request $request)
{
return view('hello.create')->with('a_variable', $request->a_variable);
}
or injecting the variable in the method:
public function create(Request $request, $a_variable)
{
return view('hello.create')->with('a_variable', $a_variable);
}
Option 2
For the use of query params, you should include this options when making the request. If your route looks like this:
Route::get('hello/create', 'HelloController#create');
You could specify query params like this:
GET www.my-domain.com/hello/create?first_parameter=value_1&second_parameter=value_2
So in your controller you access this values like this:
public function create(Request $request)
{
$value_1 = $request->get('first_parameter');
$value_2 = $request->get('second_parameter');
return view('hello.create')
->with('value_1', $value_1)
->with('value_2', $value_2);
}
You are alreading sending data to view using with().
Echo it in your view file using $variablename set in with() Example: <?php echo $title; ?>

how can i use same route for two different controller function methods in laravel

how can i use same route for two different controller function methods in laravel
first controller
public function index()
{
$comproducts = Comproduct::paginate(6);
$items = Item::orderBy('name')->get();
return view('computer', compact(['comproducts', 'items']));
}
second controller
public function index()
{
return view('search.index');
}
i want to use these two different controller functions for one route.
This is my route name
Route::get('/computer', [
'uses' => 'ComputerProductsController#index',
'as' => 'computer.list'
]);
laravel needs somehow to identify which exactly method you want. for example you can pass the parameter, which will identify which method to call.
public function index(Request $request)
{
// if param exists, call function from another controller
if($request->has('callAnotherMethod')){
return app('App\Http\Controllers\yourControllerHere')->index();
}
$comproducts = Comproduct::paginate(6);
$items = Item::orderBy('name')->get();
return view('computer', compact(['comproducts', 'items']));
}
You can't. If you want to add search functionality to your first controller's index page, you should determine which page to show inside your controller.
A possible example controller:
public function index(Illuminate\Http\Request $request)
{
// If the URL contains a 'search' parameter
// (eg. /computer?search=intel)
if ($request->has('search')) {
// Do some searching here and
// show the search results page
return view('search.index');
}
$comproducts = Comproduct::paginate(6);
$items = Item::orderBy('name')->get();
return view('computer', compact(['comproducts', 'items']));
}

Empty route leeds to 404-Error - SilverStripe 3.5

Like superficial descriped in SilverStripe Docs, I'm trying to set a custom controller for my homepage.
I changed the default homepage link to 'custom-home' and added those two routes.
The second one, with the path in it works and directs me to my controller. The first (empty) one just sends me to an 404-error page.
Couldn't figure out how to fix that. Any suggestions?
routes.yml
Director:
rules:
'': 'MyHome_Controller'
'custom-home': 'MyHome_Controller
_config.php
RootURLController::set_default_homepage_link('custom-home');
MyHome_Controller.php
<?php
class MyHome_Controller extends Page_Controller {
private static $allowed_actions = [];
private static $url_handlers = [];
public function init() {
parent::init();
}
public function Link($action = null) {
return Director::baseURL() . 'custom-home';
}
public function index() {
$data = [
'Title' => 'Hello World',
'ClassName' => __CLASS__,
];
return $this
->customise($data)
->renderWith([__CLASS__, 'Page']);
}
}
I believe the way the empty route (RootURLController) works is that you're telling it the URLSegment of a page in the CMS that should resolve to the root URL. So I think what you need to do is go into the CMS and change the URLSegment of your CustomHomePage to 'custom-home'.

Getting the controller action before behaviour code runs in Yii2

I'm trying to execute some code inside a Yii2 controller as I need some code from the model to be accessible within the behaviors section so I can pass the model as a parameter and avoid running duplicate queries; however I also need to be able to find out what action is being called, but I am not having much luck.
I have tried using beforeAction but it seems this gets run AFTER the behaviours code runs, so that doesn't help me.
I then tried using init, but it seems the action isn't available via $this->action->id at that point.
Some example code:
class MyController extends Controller {
public $defaultAction = 'view';
public function init() {
// $this->action not available in here
}
public function beforeAction() {
// This is of no use as this runs *after* the 'behaviors' method
}
public function behaviors() {
return [
'access' => [
'class' => NewAccessControl::className(),
'only' => ['view','example1','example2'],
'rules' => [
[
'allow' => false,
'authManager' => [
'model' => $this->model,
'other_param' => $foo,
'other_param' => $bar,
],
'actions' => ['view'],
],
// everything else is denied
],
],
];
}
public function viewAction() {
// This is how it is currently instantiated, but we want to instantiate *before* the behavior code is run so we don't need to instantiate it twice
// but to be able to do that we need to know the action so we can pass in the correct scenario
$model = new exampleModel(['scenario' => 'view']);
}
}
authManager is simply a reference to a member variable inside an extension of the AccessRule class.
Is there anyway I can do this?
Well, if I get you right, you are looking for something like this:
public function behaviors()
{
$model = MyModel::find()->someQuery();
$action = Yii::$app->controller->action->id;
return [
'someBehavior' => [
'class' => 'behavior/namespace/class',
'callback' => function() use ($model, $action) {
//some logic here
}
]
];
}
Because behaviors() is just a method, you can declare any variables and add any logic that you want in it, the only one convention that you must follow - is that return type must be an array.
If you use your custom behavior, you are able to use events() method where you can bind your behavior's methods to certain events. E.g.
class MyBehavior extends Behavior
{
public function events()
{
return [
\yii\web\User::EVENT_AFTER_LOGIN => 'myAfterLoginEvent',
];
}
public function myAfterLoginEvent($event)
{
//dealing with event
}
}
In this example myAfterLoginEvent will be executed after user successfully login into application. $event variable will be passed by framework and depending of event type it will contain different data. Read about event object
UPDATE:
As I can see now my answer was more generic about events and behaviors. And now when you added code, I can suggest to you to override behavior's beforeAction($action) method with the following code:
public function beforeAction($action)
{
$actionID = $action->id;
/* #var $rule AccessRule */
foreach ($this->rules as &$rule) {
$model = &$rule->authManager['model'];
//now set model scenario maybe like this
$model->scenario = $actionID;
}
//now call parent implementation
parent::beforeAction($action);
}
Also take a look at AccessControl implementation of beforeAction method, it invokes for each rule allows method with passing current action to it as a parameter. So if you have class that extends AccessRule, you can either override allows($action, $user, $request) method or matchCustom($action) method to set appropriate model scenario. Hope this will help.
One more alternative:
override controller's runAction($id, $params = []) method. Here $id is actionID - exactly what you need. Check id, set appropriate model scenario and call parent::runAction($id, $params);

suggestion on restful laravel

I am recently started using laravel, i am using following restful approach, please suggest if this approach is good...
Author controller
class AuthorsController extends BaseController {
public $restful = true;
public function getIndex()
{
return View::make('authors.index')->with('title', 'Showing Authors')->with('authors', Author::all());
}
public function newAuthor()
{
if(Request::isMethod('post')){
$author = Author::create(array(
'name' => Input::get('name'),
'bio' => Input::get('bio')
));
if($author->id) return Redirect::route('authors')->with('message', 'The Author was created successfully!');
}
else{
return View::make('authors.new')->with('title', 'New Author');
}
}
}
Routes
Route::get('authors', array('as' => 'authors', 'uses' => 'AuthorsController#getIndex'));
Route::match(array('GET', 'POST'), 'authors/new', array('as' => 'new_author', 'uses' => 'AuthorsController#newAuthor'));
Please suggest if i am using correct approach for create method, and i am using same method for add form and post request.
thanks.
Your code probalby works, but you could improve it by joining your routes, controllers and migrations in one resource.
With laravel generator package
After installing that package, with the following command:
Route::resource("path","SomeController");
You will get generated resources for you app. That includes list of restful controller actions.
For example you for main GET method you will have generated index action in you controller.
Close. You shouldnt need to test the request method in a controller action if the routes/controller is set up properly.
Author Controller
class AuthorsController extends BaseController {
public function getIndex()
{
return View::make('authors.index')->with('title', 'Showing Authors')->with('authors', Author::all());
}
public function getNew()
{
return View::make('authors.new')->with('title', 'New Author'); //this view should contain a form that POST's to /authors/new
}
public function postNew() {
$author = Author::create(Input::all()); //note: use $fillable on your model here to prevent any extra fields from breaking things
return Redirect::action('AuthorsController#getNew')->with('message', 'The Author was created successfully!');
}
}
Routes
Route::controller("/authors", "AuthorsController")

Categories