I have a problem with routes in Laravel. I am working on DMS (Document Management System), I need to make folders and infinite sub-folders.
This leeds me to block the way to make hundreds or thousands of routes to achieve the goal.
I need to make fully dynamic routes as the following example:
('/folders',[FolderController::class , 'index']) //to retrieve all folders
('/folders/{x}' , [FolderController::class , 'show']) // to retrieve level one sub-folder
('/folders/{x}/{y}' ,[FolderController::class , 'xyz']) // to retrieve level two sub-folder
This leeds me to make infinite routes for each sub-folders level.
How to make dynamic routes for dynamic sub-folders level?
Thanks in advance.
You can use a wildcard parameter:
Route::get('/folders/{x}' , [FolderController::class , 'show'])
->where('x', '.*');
then your controller route would be:
public function show($x = '') {
$path = explode('/', $x);
// $path is an array with the directory structure
// Do whatever you want with it e.g.
if (empty($path)) {
return $this->index();
}
}
Don't do this you will end up with a lot a route and performance issues. Instead do only one route with an optional parameters as the parent folder.
'/folders/{x?}' , [FolderController::class , 'show']);
In your db every folder should have an id and a parent id.
when the parent id is null this mean it's a root folder.
Then you can recursively get all the child/parent folder
Related
I have this route in web.php
Route::group(['prefix'=>'agent','namespace'=>'Agent','middleware'=>
['auth','agent'],'as'=>'agent.'], function()
{
Route::get('/dashboard',[AgentController::class, 'index'])->name('dashboard');
Route::resource('/properties', PropertyController::class);
});
When I run the command below,
php artisan route:list
I got this error:
Illuminate\Contracts\Container\BindingResolutionException
Target class [Agent\App\Http\Controllers\PropertyController] does not
exist.
at
C:\xampp\htdocs\sweethomeFinal\vendor\laravel\framework\src\Illuminate\Container\Container.php:879
875▕
876▕ try {
877▕ $reflector = new ReflectionClass($concrete);
878▕ } catch (ReflectionException $e) {
879▕ throw new BindingResolutionException("Target class [$concrete] does
not exist.", 0, $e);
880▕ }
881▕
882▕ // If the type is not instantiable, the developer is attempting to resolve
883▕ // an abstract type such as an Interface or Abstract Class and
there is
1 [internal]:0
Illuminate\Foundation\Console\RouteListCommand::Illuminate\Foundation\Console{closure}(Object(Illuminate\Routing\Route))
2
C:\xampp\htdocs\sweethomeFinal\vendor\laravel\framework\src\Illuminate\Container\Container.php:877
ReflectionException::("Class Agent\App\Http\Controllers\PropertyController does not exist")
But when I put the "Route::resource('/properties', PropertyController::class);" outside the auth
Route::group(['prefix'=>'agent','namespace'=>'Agent','middleware'=>
['auth','agent'],'as'=>'agent.'], function()
{
Route::get('/dashboard',[AgentController::class, 'index'])->name('dashboard');
});
Route::resource('/properties', PropertyController::class);
It just shows all the route lists. But I wanted to put it inside the auth, may I know what is wrong?
Group namespaces made sense pre-Laravel 8, but now with the suggested way of defining routes as Controller::class the prefixes are basically useless.
Routing before Laravel 8
Before v8, Laravel used a default prefix defined in RouteServiceProvider of App\Http\Controllers\. This meant that you only needed to provide the last part - MyController and it was automatically built out to the fully qualified class name (App\Http\Controllers\MyController).
Routing beginning in v8
In v8, the default controller path was removed ($namespace = null), meaning you have to provide the fully qualified class name yourself, or add the prefix back to the service provider. The most efficient way to do this is using the ::class syntax which returns the required name. This method of providing the class name is also more IDE friendly, which was one of the main reasons for the switch.
The problem with route group namespaces
In the older way of building out the controller class name, the group namespaces were useful for sub folders in your controllers folder.
The path would get built out like:
{default_prefix} + {group_namespace} + {controller name}
Yielding:
App\Http\Controllers\ + Agent\ + PropertyController.
This is actually still how it works in version 8; however, you're providing the values in a different way:
(null) + Agent + App\Http\Controllers\PropertyController, which doesn't make the right path.
Summary
When using the ::class syntax for Laravel routes, group level namespace prefixes really don't make sense to use anymore.
If you browse the versions of the Laravel documentation, you'll also notice that the usage of group namespaces present in version 7 is not included in the version 8 docs, because even though it still "works", it's not very useful.
when you set namespace for a route group, all the routes in this group take that namespace as prefex for it's name.
remove ,'namespace'=>'Agent' form the group definition, it should solve it.
see laravel doc for more details.
your are using laravel 8. add the below line on your web.php .
use App\Http\Controllers\yourcontrollername;
I already created a symbolic link to access the public folder from storage storage/app/public
php artisan storage:link
This time I'm having questions on my mind on how to filter users who can view the image? Like, How can I implement Only Me, My Friends Only?
Any ideas Sirs?
NOTE: There is a little performance issue with this solution. This is just to answer the question, scroll down more to see other approach from other.
<input type="file" name="file">
I personally save the files inside /storage/app/files not inside the /public folder (As it tells public for everyone).
request()->file->storeAs('files', 'filename.ext');
To view & add restrictions: create a route responsible for viewing:
Route::get('files/{$filename}', 'FileController#show')->name('files.show);
Controller:
public function show($filename)
{
$path = storage_path('app/files/'.$filename);
//do some If-Else or Filters here, for user who can access the file
return response()->download($path, null, [], null);
}
To delete the file:
File::delete('app/files/'.$filename);
i think you should set a field 'image_option' in your table 'storage_file'.
image_option: string,
image_option = {privacy_level:[1, 2, 3]}
privacy_level = 1 // public
privacy_level = 2 // only me
privacy_level = 3 // only friend only
I'm using Codeigniter. Basically what I want is to remove the Controller name (Home) from the url.
Those urls look like:
http://localhost/mechanicly/Home
http://localhost/mechanicly/Home/about
http://localhost/mechanicly/Home/contactus
now there are two ways I can remove the Home controller:
static definition of every url inside route:
$route['about'] = "Home/about";
$route['contactus'] = "Home/contactus";
I can use call backs in routes in Codeigniter:
$route['(.+)'] = function ( $param ) {
if( strpos( $param, "Admin" ) !== false ) {
echo $param;
return "Admin/".$param;
}
else{
echo $param;
return "Home/".$param;
}
};
this logic is much better as it is generic and I don't have to create new routes every time for new method inside the controller.
It is working fine for the client controller which is Home but I have another controller named as Admin and I want to redirect Admin requests to the Admin controller and Home request to the Home Controller.
Why does above code work fine for the Home controller but returns
not found
when I validate for the Admin controller?
I am using CI version 3.x
If you really want to get crazy, you could parse the methods from the controller file and programatically create the "static" approach.
Pseudo code here
$controller_file_contents = file_get_contents('path/to/controller.php');
$controller_methods = function_that_parses_methods_from_file($controller_file_contents);
foreach ($controller_methods as $controller_method) {
$route[$controller_method] = "Home/" . $controller_method;
}
How function_that_parses_methods_from_file works is probably gonna involve a regex, something like function \w+. If you go with this approach, try to keep the controller as small as possible by offloading as much logic as possible into models, which is often a good idea anyways. That way the performance impact in the router is as small as possible.
Alternatively, you may be able to parse the controller using get_class_methods if you can figure out how to load the controller into memory inside the router without conflicting when you need to load the controller using the router or causing too much performance issues.
Pretty goofy, but every method you create in that controller will automatically create a route.
you can create your menu(url´s) from db like
tbl_menu tbl_level
---------- -------------
id id
fk_level level
name dateUP
dateUP active
active
In your controllers you need to call the correct menu by session or wherever you want
then you can has this in your route.php
$route['(.+)'] = 'int_rout/routing/' . json_encode($1);
in your controller Int_rout.php
public function routing ( $param ) {
$routing = json_decode($param);
$routing = explode('/', $routing);
//$menu -> get menu from model
foreach($menu as $item){
if($routing[0] === $item->name){
//$level -> get level from model
$redirect = $level->level;
}
}
//the final redirect will be like
//admin/user or admin/user/12
//public/us
$params = ( empty($routing[1])) ? '' : '/' . $routing[1];
redirect($redirect . '/' . $routing[0] . $params, 'refresh');
}
This is my first time using stackoverflow. I am really stuck on a seemingly simple problem in Laravel 4.2, how to route to a bunch of files(.php view files in a subdirectory.
I have about forty .blade.php files in a subdirectory called mechanics.
When the clicks on the link
action('PagesController#mechanicspages') (Note: I don't know how to pass a value from here). The route is
Route::get('/mechanics/{id}', 'PagesController#mechanicspages');
The function at the PagesController is:
public function mechanicspages($id)
{
return View::make('/mechanics/{$id}');
}
Can I show a view with this logic?
To do this you need to use the find the object and send it to the view...
To access a view in a subfolder you just use a period "."
Here is what I would do:
Route file:
Route::get('/mechanics/{id}', 'PagesController#mechanicspages');
Controller File:
public function mechanicspages($id) {
$mechanic = Mechanics::find($id);
if($mechanic)
return View::make('mechanics.subview')->with($mechanic);
}
For more on this see:
How to pass data to view.
http://laravel.com/docs/4.2/responses (half way down. Search for "with")
I have two routes that are satisfying two different urls. how can i remove ambiguity?
Depending on which is first in the list is which is being picked up.
downloadFile and isEdit as both nullable bool.
context.MapRoute("Asset_GetImage", "Admin/{controller}/{action}/{assetId}/{downloadFile}");
context.MapRoute("News_Read", "Admin/{controller}/{action}/{newsId}/{isEdit}");
thanks
You don't need separate routes at all; you are collecting the exact same data types in each.
Just change assetId and newsId both to simply id and code your controllers accordingly. The controller name is already in the URL.
you could make the routes more specific.
For example, specify the {controller} for each of these:
context.MapRoute("Asset_GetImage", "Admin/Asset/{action}/{assetId}/{downloadFile}");
context.MapRoute("News_Read", "Admin/News/{action}/{newsId}/{isEdit}");
you just need to make sure the controller default is added.
as an example from one of my apps:
routes.MapRoute(
"Calendar",
"Account/Calendar/{Year}/{Month}",
new { controller = "Account", action = "Calendar", Year = DateTime.Now.Year, Month = DateTime.Now.Month }
);
{controller} and {action} aren't in the route but the defaults are still set so it knows what to do with it