I have an application where I will be storing links in the database allowing the user to assign actions to the link. I want to avoid the situation where the action does not exist and I get this error;
Action App\Http\Controllers\PermissionController#index2 not defined.
So I would like to check whether an action exists and has route. If possible in blade but anywhere else is fine.
There isn't any built in way to do this. But we have a action helper method which generates route url based on the controller action. We can make use of this and create a simple helper function to achieve the same result. The method also checks if the given controller method is linked to a route, so it does exactly what you need.
function action_exists($action) {
try {
action($action);
} catch (\Exception $e) {
return false;
}
return true;
}
// Sample route
Route::get('index', 'TestController#index');
$result = action_exists('TestController#index');
// $result is true
$result = action_exists('TestController#index1');
// $result is false
You could also verify the existence of the action method using the class directly, but this would return true if the method exists but isn't linked to a route.
Related
I'm aware there's a similar post to this but just to confirm my understanding.
I just start using Yii2 PHP. I've used dektrium/yii2-user that can login and register. I want to do a beforeAction() to check logged user auth.key if exist in database (XAMPP MYSQL). Below is the code I want to performed on.
//Action direct to json.php.
public function actionJson()
{
return $this->render('json');
}
If the statement true will direct to the page, else shows a alert error.
I know the exact code is
public function beforeAction($action){}
What I'm confused on is where do I actually put beforeAction() at.
BeforeAction()
This method is invoked right before an action is executed.
https://www.yiiframework.com/doc/api/2.0/yii-base-controller#beforeAction()-detail
Where to place it?
You must place it inside your login controller (LoginController.php) class.
Remember to call the parent inside the function as :
public function beforeAction($action)
{
if (!parent::beforeAction($action)) {
return false;
}
return true; // or false to not run the action
}
Then all the actions from that controller will use your custom beforeAction function.
I have a PagesController with one action: view.
This action accepts a page argument.
What I want to achieve:
Have a routes example.com/about and example.com/foobar.
When one of this routes is triggered, pass a value predefined in routes file to PagesController#view.
In my routes file:
Route::get('about', function () {
return App::make('App\Http\Controllers\PagesController')->view('about');
})->name('aboutPage');
Route::get('foobar', function () {
return App::make('App\Http\Controllers\PagesController')->view('foobar');
})->name('foobarPage');
It works as expected, but I want to know is there a better and more proper way to achieve the same functionality?
Pass your pages as route parameter:
Route::get('{page}', 'PagesController#view');
//controller
public function view($page)
{
//$page is your value passed by route;
return view($page);
}
So you just want an argument to your action. You can use optional parameters if that argument can be empty. You can read more about it here.
Route::get('{argument?}', 'PagesController#view')->name('page');
And in your PagesController:
public function view($argument = 'default') {
// Your logic
}
The accepted answer is what you want based on what you are doing.
If you really wanted a hardcoded value you can use the 'actions' array part of the route if you wanted.
Route::get('something', ['uses' => 'Controller#page', 'page' => 'something']);
public function page(Request $request)
{
$page = $request->route()->getAction()['page'];
...
}
asklagbox - blog - random tips and tricks
If you don't need the names of the routes like in your example
->name('foobarPage');
you can use something like this
Route::get('{page_name}','PagesController#view')->where('page_name', '(about)|(foobar)');
This will accept only the values passed in the regular expression for the page_name parameter. Other routes will throw a 404 error. I should mention that this technique seems to be valid for applications with one level of url nesting only and should NOT be used as a pattern.
From what I can see above if all you are doing is showing the correct view I would go for
Route::get('{page}', function($page)
{
if (view()->exists($page)) {
return view($page);
}
return abort(404);
});
This prevents you even needing a method in your controller.
I want to create dynamic pages CMS for my Laravel app. Admin is allowed to provide any URI for any page, so for example, he can create page with one/two/three URI and http://example.com/one/two/three will point to this site. I already figured out it's possible to add single route for multiple level URLs like this:
get('{uri}', 'PageController#view')->where('uri', '.+');
Now, I also want to have /{username} URLs to point to users profiles. That means, if I need to make it work together. For me, the perfect code would be something like this:
get('{username}', 'ProfileController#view');
get('{uri}', 'PageController#view')->where('uri', '.+');
Then, in ProfileController I'd like to make my route go further just like it wasn't there. Something like this:
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
}
}
Can it be done with Laravel?
I can think of another solution, just to have dynamic routing controller for both usernames and page uris mapping, but I would prefer to have it as separate routes.
You can resolve a new PageController instance out of the Service Container if $user is null.
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
$params = []; // If your view method on the PageController has any parameters, define them here
$pageController = app(PageController::class);
return $pageController->callAction('view', $params)
}
}
This way, the {username} route will stay but will show custom content defined by the admin.
Edit:
If you don't want to call a controller manually, you could analyze the current URL segments and check for an existing user before you define your route. In order to not make your routes.php file too complex, I'd add a dedicated service class that analyzes your URL segments:
App\Services\RouteService.php:
<?php
namespace App\Services;
class RouteService {
public static function isUserRoute()
{
if(count(Request::segments()) == 1)
return !! User::whereUsername(Request::segment(1))->first();
}
return false;
}
}
routes.php:
<?php
use App\Services\RouteService;
if(RouteService::isUserRoute())
{
get('{username}', 'ProfileController#view');
}
get('{uri}', 'PageController#view')->where('uri', '.+');
I have not tested this, but it should work. Adjust the RouteService class to your needs.
I'm using the first approach in my CMS and it works realy well. The only difference is that I have written a Job that handles all incoming requests and calls the controller actions respectively.
I have a Controller witch contains more than 150 functions. almost all of the functions inside the controller are returning views.
each view should change if the user is logged in.
I almost handled this in the view side by using parent blades and etc. But in the controller side for almost every function i should check if the user is logged in and return some specific data about the user along with the view.
for example:
$user=[];
if(Auth::check())
{
$user=Auth::user;
$reputation=$user['reputation'];
$messages=$user->messages();
$notifications=$user->notification();
}
return view('pages.profile')->with(['user'=>$user , 'messages'=>$messages , 'notifications'=>$notifications]);
I thought that this is possible using middlewares but i could not figure it out.
what are the alternatives here?
for more information i am using laravel 5.
One solution could be using your custom function instead of view(). Sth like:
//in your controller action
public function someAction() {
return $this->view('pages.profile');
}
protected function view($template, $data = array()) {
return view($template)->with($data)->with([data that needs to be passed to all views]);
}
I'm new to Zend 2, I started first with laravel and I need something to do that I know Laravel's Route Filter can solve but I'm using Zend 2.
Laravel Route Filter
I checked the documentation of Zend 2 and I can't seem to find it.
I need to do some logging and stuffs only on selected routes and I don't want to add that code on every actions of every routes because I have over 50 different routes here, but in laravel I could make use of route filter so that in selected routes, it will go first in the filter before going to that route.
In laravel's route:
Route::get('route1',array('before'=>'generic','uses'=>'GenericController#getIndex'));
Route::get('route2',array('before'=>'generic','uses'=>'GenericController#getIndex'));
Route::filter('generic', 'RouteFilter');
I have not used Laravel before, but I followed to the link and I am very afraid to say that,
No, it does not exist
You will have use the controller:
public function somethingAction()
{
if (!condition true) {
return $this->notFoundAction();
// or return $this->redirect()->toRoute('MyRoute');
}
// Route is filtered
}
You can also attach a callback to the MvcEvent::EVENT_ROUTE event:
public function(MvcEvent $e)
{
$e->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function(EventInterface $e) {
// check the route and do whatever you like
$matchedRouteName = $event->getRouteMatch()->getMatchedRouteName();
if ($matchedRouteName = 'admin') {// or whatever you want to check
// check if user is admin
}
});
}
Not only MvcEvent::EVENT_ROUTE, there are a lot of events triggered such as MvcEvent::EVENT_DISPATCH. You just need to attach a callback function!
For, full list of all the Mvc Events, view this link!