laravel 5 nested routing issue - php

New to Laravel 5, and building a little Rest test app. So I'm envisioning 2 different endpoints for a single controller.
/myApp/public/index.php/states/{state}/cities //returns cities in a state
and
/myApp/public/index.php/states/{state}/cities/{city} //will do somethin else
its a little unclear to me how to set up the routes for this. I suppose I could have these endpoints use the same controller method, but it seems like better architecture to just route each to its own method.
So far, I've got 2 things that each individually work, but dont work together:
in routes.php
//route to the first endpoint
Route::resource('states.cities', 'StatesController');
//routes to the second endpoint if first is uncommented,otherwise blank page with no errors in log
Route::resource('states.cities', 'StatesController#cities');
And the relevant part of my controller code:
class StatesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index(Request $request, $state)
{
//works
$cities = States::where('state', '=', $state)->lists('name');
echo json_encode($cities);
}
public function cities(Request $request, $state, $city)
{
echo "second request";
echo $state;
echo $city;
}
......
Any one have any ideas on the proper way to handle this going forward? Cheers!

Try this.
Route::get('states/{state}/cities', [
'as' => 'state.cities',
'uses' => 'StatesController#index'
]);
And second.
Route::get('states/cities/{state}/{city}', [
'as' => 'city.of.state',
'uses' => 'StatesController#cities'
]);
Note: There is no need to use resource route in this case. The resource routes creates the whole array of different routes which you really don't need. Resource controllers

Related

laravel- how to pass data to starter kit - dashboard

im new to laravel, im using laravel starter kit - i added "profile resource" simalar to "chirps" on
this bootcamp : laravel bootcamp with all relations 1:1 and so on.
but now im trying to pass the profile data to dashboard, fields like "about" "skills".
i have a working query, but i cant find way to use it in dashboard.
thiss the "profile-controler-index-method" its working but i only know how to use it with "index.vue" of "profile.vue" i couldnt use it with "dashboard.vue" because i just need the data not the whole vue script :
public function index()
{
return Inertia::render('Profile/Index', [
'Profile' => profile::with('user:id,name')->get(),
]);
}
and thiss my query :
DB::select('select * from profiles where user_id = 23');
after many loging trying to find the controller of dashboard or somthing helpfull, i found this file that gets loaded everytime i refresh "dashboard" "RouteServiceProvider"
/**
* The path to the "home" route for your application.
*
* Typically, users are redirected here after authentication.
*
* #var string
*/
public const HOME = '/dashboard';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*
* #return void
*/
public function boot()
{
Log::info('infooo im here 1');
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
==============Edit :
i just found out that i can render any page i want in the index method.. whaaat..
public function index()
{
return Inertia::render('Dashboard', [
'Profile' => profile::with('user:id,name')->get(),
]);
}
so if i can add some parameter to the index method .. i can render diffrent pages is this okey?
its so confusing these router and render terms..
i think i solve it, but im not sure if thiss right .. if you have better way plz answer.
i redirect the route
Route::get('/dashboard', function () {
//return Inertia::render('Dashboard');
return redirect('dashboards');
})->middleware(['auth', 'verified'])->name('dashboard');
to this route
Route::resource('dashboards', DashboardController::class)
->only(['index'])
->middleware(['auth', 'verified']);
now i have "dashboards" instead of "dashboard" and i can pass through it but something seems not right ..

Policy with route group keeps returning 403

I'm trying to use policy on a route group. I've included the bindings middleware and tried to list the ACTION and MODEL in the CAN middleware.
For some reason it keeps returning 403. Probably I didn't quite understood how the policies work.
I'm trying to enter the before method in the policy but It keeps returning 403. Also it would be lovely if someone explains how exactly should I list custom methods in the middleware.
I also did register my policy in the AuthServiceProvider
protected $policies = [
Service::class => ServicePolicy::class,
];
public function before(CustomAuth0User $user, Service $service)
{
dd($service);
}
Route::group(['prefix' => 'services', 'namespace' => 'Services', 'middleware' => ['bindings', 'can:getCancel, service']], function () {
Route::get('/{service}/cancel', 'ServiceController#getCancel');
Route::post('/{service}/cancel', 'ServiceController#postCancel');
Route::get('/{id}/reassign', 'ServiceController#getReassign');
Route::post('/{id}/reassign', 'ServiceController#postReassign');
Route::get('/{id}/close', 'ServiceController#getClose');
Route::post('/{id}/close', 'ServiceController#postClose');
Route::get('/{id}/history', 'ServiceController#getHistory');
});
Controller
public function getCancel(Service $service)
{
dd($service);
}

Laravel Validation - Rule to disallow request parameters

In my Laravel 5.8 app I have many API routes which return paginated results. If I make a request to my API appending the following query string I can disable pagination.
http://api.test/users/?no_paginate=1
My question is... how can I disable no_paginate from being used on certain routes? I'd preferbly want some validation to go in the request class but I can't find anything in the docs for that.
You can do this using a Global Middleware.
Create a DisableNoPaginate Middleware:
php artisan make:middleware DisableNoPaginate
Then define what the middleware should do (DisableNoPaginate.php):
<?php
namespace App\Http\Middleware;
use Closure;
class DisableNoPaginate
{
public function handle($request, Closure $next)
{
//remove no_paginate param from request object
unset($request['no_paginate']);
return $next($request);
}
}
Arrange for the middleware to run on all routes (routes.php):
$app->middleware([
App\Http\Middleware\DisableNoPaginate::class
]);
Now the no_paginate query param should be stripped from all your incoming requests.
For the best approach to get users either paginate or get all listing by below code in UsersController
public function index($type = null, Request $request)
{
$builder = User::where(/*query*/);
if($type == "paginate") {
$items = $builder->paginate(10);
} else {
$items = $builder->get();
}
return view("users.index", ['users' => $items]);
}
Here is the route in web.php/api.php file
Route::get('/{type?}', ['as' => 'users.index', 'uses' => 'UsersController#index']);
Here url will be
http://api.test/users/paginate // get pagination response.
http://api.test/users // get response without pagination
I think this will help you.

Organizing Controllers in laravel

I recently dove into the world of laravel (version 5.4). While initially confused, the concept of MVC makes a lot of sense in writing large applications. Applications that you want to be easily understood by outside developers.
Using laravel for this has greatly simplified coding in PHP and has made the language fun again. However, beyond dividing code into its respective models, views, and controllers, what happens if we need to divide controllers to prevent them from growing too large?
A solution that I have found to this is to define one controller each folder and then fill that controller with traits that further add functionalities to the controller. (All-caps = folder):
CONTROLLER
HOME
Controller.php
TRAITS
additionalFunctionality1.php
additionalFunctionality2.php
additionalFunctionality3.php
...
ADMIN
Controller.php
TRAITS
additionalFunctionality1.php
additionalFunctionality2.php
additionalFunctionality3.php
...
Within routes/web.php I woud initialize everything as so:
Route::namespace('Home')->group(function () {
Route::get('home', 'Controller.php#loadPage');
Route::post('test', 'Controller.php#fun1');
Route::post('test2', 'Controller.php#fun2');
Route::post('test3', 'Controller.php#fun3');
});
Route::namespace('Admin')->group(function () {
Route::get('Admin', 'Controller.php#loadPage');
Route::post('test', 'Controller.php#fun1');
Route::post('test2', 'Controller.php#fun2');
Route::post('test3', 'Controller.php#fun3');
});
With me being new to laravel, this seems like a simple and elegant way to organize my logic. It is however something I do not see while researching laravel controller organization.
The Question
Is there an issue, both in the short-run and in the long-run, of organizing my data like this? What is a better alternative?
Example Controller:
<?php
namespace App\Http\Controllers\Message;
use DB;
use Auth;
use Request;
use FileHelper;
use App\Http\Controllers\Message\Traits\MessageTypes;
use App\Http\Controllers\Controller;
class MessageController extends Controller
{
// Traits that are used within the message controller
use FileHelper, MessageTypes;
/**
* #var array $data Everything about the message is stored here
*/
protected $data = []; // everything about the message
/**
* #var booloean/array $sendableData Additional data that is registered through the send function
*/
protected $sendableData = false;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('access');
}
/**
* Enable sendableData by passing data to the variable
*
* #param array $data Addition data that needs to registrered
* #return MessageController
*/
protected function send ($data = []) {
// enable sendableData by passing data to the variable
$this->sendableData = $data;
return $this;
}
/**
* Enable sendableData by passing data to the variable
*
* #param string $type The type of message that we will serve to the view
* #return MessageController
*/
protected function serve ($type = "message") {
$this->ss();
$this->setData(array_merge($this->sendableData, $this->status[$type]));
$this->data->id = DB::table('messages')->insertGetId((array) $this->data);
}
/**
* Set the data of the message to be used to send or construct a message
* Note that this function turns "(array) $data" into "(object) $data"
*
* #param array $extend Override default settings
* #return MessageController
*/
protected function setData(array $extend = []) {
$defaults = [
"lobby" => Request::get('lobbyid'),
"type" => "text",
"subtype" => null,
"body" => null,
"time" => date("g:ia"),
"user" => Auth::User()->username,
"userid" => Auth::User()->id,
"day" => date("j"),
"month" => date("M"),
"timestamp" => time(),
"private" => Request::get('isPrivate') ? "1" : "0",
"name" => Request::get('displayname'),
"kicker" => null
];
$this->data = (object) array_merge($defaults, $extend);
// because a closure can not be saved in the database we will remove it after we need it
unset($this->data->message);
return $this;
}
/**
* Send out a response for PHP
*
* #return string
*/
public function build() {
if($this->data->type == "file") {
$filesize = #filesize("uploads/" . $this->data->lobby . "/" . $this->data->body);
$this->data->filesize = $this->human_filesize($filesize, 2);
}
// do not send unneccessary data
unset($this->data->body, $this->data->time, $this->data->kicker, $this->data->name, $this->data->timestamp);
return $this->data;
}
/**
* Send out a usable response for an AJAX request
*
* #return object
*/
public function json() {
return json_encode($this->build());
}
}
?>
Laravel architecture is simple enough for any size of the application.
Laravel provides several mechanisms for developers to tackle the fatty controllers in your Application.
Use Middlewares for authentications.
Use Requests for validations and manipulating data.
Use Policy for your aplication roles.
Use Repository for writing your database queries.
Use Transformers for your APIs to transform data.
It depends on your application. if it is too large and have different Modules or functionalities then you should use a modular approach.
A nice package is available for making independent modules here
Hope this helps.
I think you should do a little differently ! First you should use your traits at the same levels as the controllers since traits are not controllers, your tree should look more like :
Http
Controller
Controller.php
Home
YourControllers
Admin
Your admin controllers
Traits
Your Traits
Next your routes need to be more like that :
Route::group(['prefix' => 'home'], function()
{
Route::get('/', 'Home\YourController#index')->name('home.index');
}
Route::group(['prefix' => 'admin', 'middleware' => ['admin']], function()
{
Route::get('/', 'Admin\DashboardController#index')->name('dashboard.index');
}
You can use many kink or routes like :
Route::post('/action', 'yourControllers#store')->name('controller.store');
Route::patch('/action', 'yourControllers#update')->name('controller.update');
Route::resource('/action', 'yourController');
The Resource route creates automatically the most used your, like post, patch, edit, index.. You just need to write the action and the controller called with its action. You can check out your toutes with this command : php artisan route:list
Laravel also has many automated features, like the creation of a controller with this command : php artisan make:controller YourController.
For the routes the prefix creates portions of url, for example all the routes inside the route group with the prefix 'admin' will lool like : www.yourwebsite.com/admin/theroute, and can also be blocked for some users with a middleware.
To get familiar with laravel i suggest you follow the laravel 5.4 tutorial from scratch by Jeffrey Way on Laracasts, he's awesome at explaining and showing how laravel works. Here is a link : https://laracasts.com/series/laravel-from-scratch-2017
Hope it helps, ask me if you want to know anything else or have some precisions, i'll try to answer you !

Unable to generate a URL

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',
...
]
);

Categories