Help me in a doubt, I have an application in laravel, and I would like to call several Controller in the same Route, is it possible?
I've tried it that way, but it does not work
$api->get('document', ['as' => 'system.api.manager.v1.document.listDoc1', 'shield' => ['system.manager.document.list'], 'any' => true, 'uses' => 'Doc1Controller#grid']);
$api->get('document', ['as' => 'system.api.manager.v1.document.listDoc2', 'shield' => ['system.manager.document.list'], 'any' => true, 'uses' => 'Doc2Controller#grid']);
$api->get('document', ['as' => 'system.api.manager.v1.document.listDoc3', 'shield' => ['system.manager.document.list'], 'any' => true, 'uses' => 'Doc3Controller#grid']);
You can use inheritance.
Define GreatController as parent of
"Doc1Controller, Doc2Controller, Doc3Controller"
then move your standart methods, functions to GreatController. I am doing that way. Also you can define all same methods in _construct()
you can use a closure instead a direct controller call. There you call your controller
Related
Using CakePHP v3.3.16
I want to write a fallback route in such a way that if URL is not connected to any action then it should go to that fallback.
Created routes for SEO friendly URL like this
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
But it's also inclute all the controller actions in it so if i try to call a controller ex: cart/index it's going to website/brands/index/index
If I have to remove exclude it, I have to create a route like this/
$routes->connect('/cart',['controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
And so on to the other controller to access.
Example:
I have a controller CartController action addCart
CASE 1
if I access URL my_project/cart/addCart/ It should go to cart controller action
CASE 2
if I access URL my_project/abc/xyz/ and there is no controller named abc so it should go to BrandsController action index
My Current routes.php looks like this
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['prefix'=>'website','controller' => 'Home', 'action' => 'index']);
$routes->connect('/trending-brands', ['prefix'=>'website','controller' => 'Brands', 'action' => 'trending']);
$routes->connect('/users/:action/*',['prefix'=>'website','controller' => 'Users'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart/:action/*',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(':controller', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->connect(':controller/:action/*', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('website', function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});
Plugin::routes();
Your edits totally invalidate my first answer, so I decided to just post another answer.
What you want to achieve can not be done by the router because there is no way for router to tell if the controller/action exists for a particular route. This is because the router just work with url templates and delegates the task of loading Controllers up in the request stack.
You can emulate this feature though by using a Middleware
that check if the request attribute params is set and then validate them as appropriate and changing them to your fallback controller if the target controller doesn't exist.
Just make sure to place the RoutingMiddleware execute before your middleware otherwise you will have no params to check because the routes wouldn't have been parsed.
Middlewares implement one method __invoke().
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Cake\Http\ControllerFactory;
use Cake\Routing\Exception\MissingControllerException;
class _404Middleware {
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
//$params = (array)$request->getAttribute('params', []);
try {
$factory = new ControllerFactory();
$controller = $factory->create($request, $respond);
}
catch (\Cake\Routing\Exception\MissingControllerException $e) {
// here you fallback to your controllers/action or issue app level redirect
$request = $request->withAttribute('params',['controller' =>'brands','action' => 'index']);
}
return $next($request, $response);
}
}
Then attach in your App\Application see also attaching middlewares
$middlewareStack->add(new _404Middleware());
please remmber to clean up the code as I didn't test it under real dev't enviroment.
After thought: if your were looking to create an error page for all not found resources, then you don't need all that, instead you would just customise the error template in Template/Error/error404.ctp.
If I have to remove exclude it, I have to create a route like this/ And so on to the other controller to access.
There is no need to specify every controller/name in the pattern, instead you can create all your specify routes first and then place the following route below them to catch all unmatched routes.
$routes->connect(':/prefix/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
And maybe another one without prefix
$routes->connect('/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
And since you mentioned that you are using 3.3.* cake version, Your routes can be written taking advatage of routes scoping
Router::prefix('website', function ($routes) {
// All routes here will be prefixed with `/prefix`
// And have the prefix => website route element added.
$routes->fallbacks(DashedRoute::class);
$routes->connect(
'/:slug',
['controller' => 'Brands', 'action' => 'index']
);
$routes->connect(
':slug/*',
['controller' => 'Products', 'action' => 'index']
});
i have one issue with the Laravel routes.
I have one function index($sport = '', $date = ''); this function shows me the news for a specific sport and date. But sometimes these parameters are not entered and I want to display all news. This works so fine so good, the problem is with the route.
This is the route code I have used:
Route::get('/news/{sport?}/{date?}.html', ['as' => 'news.index', 'uses' => 'NewsController#index']);
The problem comes when there is no sport and date entered, than the URL is domain.com/news.html, but is not caught with that code. How can i achieve that ?
If you think about news and sport as resources you could have something like that:
// index case news
Route::get('/news.html', ['as' => 'news.index', 'uses' => 'NewsController#index']);
// show case news
Route::get('/news/{date}.html', ['as' => 'news.show', 'uses' => 'NewsController#show']);
// index case sport
Route::get('/news/sport.html', ['as' => 'sport.index', 'uses' => 'SportController#index']);
// show case sport
Route::get('/news/sport/{date}.html', ['as' => 'sport.show', 'uses' => 'SportController#show']);
A different approach would be:
// index case news
Route::get('/news.html', ['as' => 'news.index', 'uses' => 'NewsController#index']);
// sport case
Route::get('/news/{sport}.html' , ['as' => 'sport.index', 'uses' => 'SportController#index'])
->where(['sport' => '[0-9]+']);
// date case
Route::get('/news/{date}.html', ['as' => 'news.show', 'uses' => 'NewsController#show'])
->where(['date' => '[0-9]{4}-[0-9]{1,}-[0-9]{1,}']);
// sport and date case
Route::get('/news/{sport}/{date}.html' , ['as' => 'sport.index', 'uses' => 'SportController#show'])
->where(['sport' => '[0-9]+', 'date' => '[0-9]{4}-[0-9]{1,}-[0-9]{1,}']);
theres so many ways todo that, but for the simplest way, just add another route for displaying all list, Route::get('/news/','NewsController#index');
If you want to keep it simple , you should try this approach
domain.com/news.html?date=2016-11-23&sport=1
if date and sport not found in url you can show all result
and it is easy readable syntax if some one want to bookmark this url.
Having the next routes:
Route::get('/apartment/{apartment_name}', 'ApartmentController#getApartmentByName');
Route::get('/apartment/create', [
'uses' => 'ApartmentController#create',
'as' => 'apartment.create'
]);
Route::get('/apartment/edit', [
'uses' => 'ApartmentController#edit',
'as' => 'apartment.edit',
]);
How could I make a difference between the routes
myapp.com/apartment/create and myapp.com/apartment/beach-apartment
I would like to search by the apartment's name with the same URI prefix (apartment/) but with this code I'm always calling the parameter route.
It is because whatever is being called, create or edit, is being matched within the parameter one, /apartment/{apartment_name}, as create or edit equals to the apartment_name.
Just move the parameter one to the lower most line within that block.
Route::get('/apartment/create', [
'uses' => 'ApartmentController#create',
'as' => 'apartment.create'
]);
Route::get('/apartment/edit', [
'uses' => 'ApartmentController#edit',
'as' => 'apartment.edit',
]);
Route::get('/apartment/{apartment_name}', 'ApartmentController#getApartmentByName');
With this configuration, if the /apartment/create or /apartment/edit is not matched, then it will match /apartment/{apartment_name}.
I'm pretty new on laravel5 and I'm trying to generate dynamically route alias under route.php
This is it:
Route::get('/menu/{category}/{product}/{item}', 'MenuController#listItem')->name('/{category}/{item}');
I already tried with with 'as' and 'uses' and I'm still getting:
/menu/{category}/{product}/{item}
With all parameters replaced by the correct values instead of:
/{category}/{item}
Expounding on what Vinicius Luiz said.
Route::get('/menu/{category}/{product}/{item}', ['as' => 'named.route' , 'uses' => 'MenuController#listItem']);
// to get the actual linke
route('named.route', ['category' => $category->id, 'product' => $product->id, 'item' => $item->id]);
depending, you may not do ->id or anything, you might just pass the whole $category, $product, etc. Depends on how the routing in your controllers is setup.
EDIT:
From your comment, it likes like you want something like:
class MenuController {
public function lisItem($category_name, $product_name) {
$category = Category::where('name', $category_name)->first(['id']);
$product = Product::where('category_id', $category->id)->where('name', $product_name')->first();
}
}
Route::get('/{category}/{item}', ['as' => 'named.route' , 'uses' => 'MenuController#listItem']);
// to get the actual linke
route('named.route', ['category' => $category->id, 'item' => $item->id]);
there is probably a better way to do the queries, but that should work for you.
Try it:
Route::get('/menu/{category}/{product}/{item}', ['as' => 'a.name.to.your.route' , 'uses' => 'MenuController#listItem']);
How can I get current route name in filter? I tried use Route::currentRouteName(); but it's null.
Route::filter('belongsToUser', function(){
dd( Route::currentRouteName() );
exit;
});
Route looks for example:
Route::get('/openTicket/{id}', array('before' => 'auth|belongsToUser', 'uses' => 'MyController#MyAction'));
Your route isn't named, so it's no surprise the route name is null. You need an as parameter.
Route::get('/openTicket/{id}', array(
'as' => 'yourRouteName',
'before' => 'auth|belongsToUser',
'uses' => 'MyController#MyAction'));
http://laravel.com/docs/routing#named-routes