How to set view file path in laravel? - laravel

I have a directory structure for laravel app like this:
app/
admin/
controllers/
views/ -> for admin views
...
views/ -> for frontend views
How can I set the view path for controllers in admin? I don't want to use View::addLocation or View::addNamespace because I might have the same view file name for admin and frontend, and don't want to add a namespace for every View::make('namespace::view.file').
I see in http://laravel.com/api/4.2/Illuminate/View/View.html there is a setPath method, but how do I call it? View::setPath raised undefined method error.

You have two ways to accomplish your goal. First, let's have a look at app/config/view.php. That's where the path(s) for view loading are defined.
This is the default:
'paths' => array(__DIR__.'/../views'),
Method 1: Load both directories
You can easily add the admin directory to the array
'paths' => array(
__DIR__.'/../views',
__DIR__.'/../admin/views
),
Now the big disadvantage of this: view names have to be unique. Otherwise the view in the path specified first will be taken.
Since you don't want to use a view namespace I suppose you don't want a syntax like admin.viewname either. You'll probably like method 2 more ;)
Method 2: Change the view page at runtime
Every Laravel config can be changed at runtime using the Config::set method.
Config::set('view.paths', array(__DIR__.'/../admin/views'));
Apparently setting the config won't change anything because it is loaded when the application bootstraps and ignored afterwards.
To change the path at runtime you have to create a new instance of the FileViewFinder.
Here's how that looks like:
$finder = new \Illuminate\View\FileViewFinder(app()['files'], array(app_path().'/admin/views'));
View::setFinder($finder);
Method 3: Use addLocation but without default path
You could also remove the default path in app/config/view.php
'paths' => array(),
And then use View::addLocation in any case (frontend and admin)
View::addLocation(app_path().'/views');
View::addLocation(app_path().'/admin/views');

In the latest version 6 i am doing it this ways:
View::getFinder()
->setPaths([
base_path('themes/frontend/views'),
base_path('themes/admin/views')]
)

In Laravel 5.5, other solutions did not work. In boot method of a service provider
View::getFinder()->prependLocation(
resource_path('views') . '/theme'
);

try it like this
View::addNamespace('admin', app_path() . '/admin/views');
Route::group(['prefix' => 'admin'], function() {
Route::get('/', function() {
return view('admin::index');
});
});

Related

Laravel views folder structure for different designs

I need some help - I want to change the whole design of my website, but I want to have the option to switch back to the old design.
My current folder structure is:
resources/views/frontend/...
I want to have the following folder structure:
resources/views/frontend/v1/...
resources/views/frontend/v2/...
In my config files I want to have a variable version, which will hold the active template version.
The problem is that now I need to use this variable in all Controllers and Views, which is a lot of work. I want to change the variable only in the Views. Does anybody have faced that situation and have a better solution for it ?
If you don't need to be able to switch the theme/design from an admin page, you can simply setup the path to your views in your config/view.php file:
/*
|--------------------------------------------------------------------------
| View Storage Paths
|--------------------------------------------------------------------------
|
| Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you.
|
*/
'paths' => [
resource_path('views'),
resource_path('theme/v1/views'),
],
Views in resources/theme/views/ will be loaded as well as the ones in the resources/views directory.
Beware of the order: the first path defined will have a higher priority if two files share the same name.
Another solution, to prevent file name collision, is to use namespaced views. In you AppServiceProvider, add this to the boot() method:
$this->loadViewsFrom(resource_path('theme2/views'), 'theme2');
See https://laravel.com/docs/6.x/packages#views
In both cases, you can use a variable in your configuration. For example, in your config/app.php:
return [
// Leave the configuration and add:
'theme' => 'v1',
];
Then, in config/view.php:
'paths' => [
resource_path('views'),
resource_path('theme/'.config('app.theme').'/views'),
],
If you want to use an environment variable (to have a different theme in local environment and production):
'paths' => [
resource_path('views'),
resource_path('theme/'.env('APP_THEME').'/views'),
],
and in your .env:
APP_THEME=v1
I've found a solution:
I've added namespaces in app\Providers\AppServiceProvider.php, in the boot method:
$this->app['view']->addNamespace('theme', base_path().'/resources/views/frontend/.config('version'));
Than I need in all Controllers and Views make some changes, but this is only one time.
In any Controller I changed from:
return view('frontend.partials.banner')->withBanner($banner);
to:
return view('theme::partials.banner')->withBanner($banner);
and in any view from:
#include('frontend.standing.partials.shorttable')
to:
#include('theme::standing.partials.shorttable')

Laravel: Creating route resource for sub directory

I am new to laravel and creating a spare parts maintenance app.
I created a route resource for spare parts using :
Route::resource('/parts' , 'SparePartsController');
This works fine.
Later I wanted to also create another route resource for spare parts categories. So I created the controller and used:
Route::resource('/parts/categories' , 'SpCategoriesController');
But this second resource wont work. When i go to www.myapp.com/parts/categories , I get a blank page. Any idea whats wrong?
Try to group the routes with a prefix for example:
Route::group(['prefix' => 'parts'], function(){
Route::get('/', 'SparePartsController');
Route::get('/categories', 'SpCategoriesController');
});
This will route all traffic from /parts to the SparePartsController and /parts/categories will call the SpCategoriesController
Look at the documentation for more information:
https://laravel.com/docs/5.3/routing#route-groups
If you want to call a specific function of the Controller just write:
Route::get('/', 'SparePartsController#functionName')
The SpCategoriesController resource route won't work because SparePartsController resource route is taking precedence over it.
To fix that, place your routes in this order:
Route::resource('/parts/categories' , 'SpCategoriesController');
Route::resource('/parts' , 'SparePartsController')
Ref: https://laravel.com/docs/5.3/controllers#restful-supplementing-resource-controllers

Subfolder routing in laravel 5

I am having trouble routing with controllers in subfolders. I have tried the solution proposed in Laravel Controller Subfolder routing, but I can't get it to work.
Folder structure
HTTP
Controllers
Admin
AdminControllers
User
UserControllers
BaseController
Admincontrollers are defined in the 'App\HTTP\Controllers\Admin' namespace
Routes file
Route::group(['middleware'=> 'admin','prefix' => 'admin'], function() {
Route::get('home', 'AdminHomeController#index');
Route::get('home', 'Admin\AdminHomeController#index');
Route::resource('events', 'AdminEventController');
Route::resource('events', 'Admin\AdminEventController');
Route::get('myevents', 'AdminEventController#myevents');
Route::get('myevents', 'Admin\AdminEventController#myevents');
Route::resource('groups', 'AdminGroupController');
Route::resource('users', 'AdminUserController');
});
This does seem weird, but it is the only way to keep it working right now.
If I delete
Route::get('myevents', 'Admin\AdminEventController#myevents');
//errormessage Class App\Http\Controllers\AdminEventController does not exist
If I delete
Route::get('myevents', 'AdminEventController#myevents');
//errormessage Action App\Http\Controllers\AdminEventController#myevents not defined.
If I put the controllers in the controller namespace (not the admin one)
I still get
//errormessage Class App\Http\Controllers\AdminEventController does not exist
When the only route added is
Route::resource('events', 'AdminEventController');
The problem were the calls in the views:
changing
<td>{!!Html::linkAction('AdminEventController#show', $event->name, $event->slug)!!}</td>
to
<td>{!!Html::linkAction('Admin\AdminEventController#show', $event->name, $event->slug)!!}</td>
fixed it.
The Laravel 5 solution in Laravel Controller Subfolder routing is correct. The problem was not in the routes file or controllers.
Yes If your application gets bigger like this, it makes sense to structure Controllers with sub-folders. But it takes a little more effort than just moving the files here and there. Let me explain the structure.
For example, we want to have a sub-folder app/Http/Controllers/Admin and then inside of it we have our AdminController.php, that’s fine. What we need to do inside of the file itself:
Correct namespace – specify the inner folder:
namespace App\Http\Controllers\Admin;
Use Controller – from your inner-namespace Laravel won’t “understand” extends Controller, so you need to add this:
use App\Http\Controllers\Controller;
Routes – specify full path
This wouldn’t work anymore:
Route::get('admin', 'AdminController#index');
This is the correct way:
Route::get('admin', 'Admin\AdminController#index');
And that’s it – now you can use your controller from sub-folder.
Reference (Tested):
http://laraveldaily.com/moving-controllers-to-sub-folders-in-a-correct-way/
By: Povilas Korop

Laravel: How to find the right blade master template?

To extend a blade template you have to write
#extends('folder.template_name')
This works for standard installation.
I've created a module for the backend and now I can't use my module template because Laravel catches the first record and that is the standard view folder.
My structure looks like this:
app
-- modules
-- modules\backend
-- modules\backend\views
-- modules\backend\views\layouts\master.blade.php
-- views
-- views\layouts\master.blade.php
So when I'm in the backend and try to display my template:
// app\modules\backend\views\page\index.blade.php
#extends('layouts.master')
Laravel renders the app\views\layouts\master.blade.php instead of
app\modules\backend\views\layouts\master.blade.php
I've tried many names inside that #extends e.g.
#extends('app\modules\backend\views\layouts\master')
#extends('app.modules.backend.views.layouts.master')
#extends(base_path(). '\app\modules\backend\views\\' . 'layouts.master')
Nothing works.
While using a package or autoloaded module, referring to it's resources is done using the double colon notation. In your case, to access the module's master template you need to use
#extends('backend::layouts.master')
These conventions are described in the docs, for further info please refer to
Laravel 4 package conventions
Make sure /app/config/view.php has a path entry for where those views are located.
I.E.
'paths' => array(__DIR__.'/../views'),
To
'paths' => array(
__DIR__.'/../views',
__DIR__.'/../modules/backend/views'
),
or whatever represents your actual path.
From here you might want to look into doing the view folder loading via another mechanism if your views are in dynamically generated folders. Maybe a module::boot event that adds the module path to the view paths array? Just an idea.

Form open to controller method - "Unknown action"

New to Laravel 4. I've created a form within a blade template and I'm following the snippet from which says that you can point a forms action to a controller method by using 'Form::open(array('action' => 'Controller#method'))'. I've created a new controller called UsersController with artisan and have created a new method within the controller named userLogin(). When I point to that method when opening a form I get an "InvalidArgumentException, Unknown action" error. If I adjust the open action to point to UsersController#index, all is well. I've run composer dump-autoload, but the issue remains.
snippet of login.blade.php:
{{ Form::open(array('action' => 'UsersController#userLogin')) }}
snippet of UsersController.php:
public function userLogin()
{
//
}
Can anyone tell me if I'm missing something?
Thanks all. Adding the following to routes.php resolved the issue:
Route::post('login', 'UsersController#userLogin');
Looks like Laravel isn't registering the action you've added, likely because you're missing a route. Try adding something like this to app/routes.php:
Route::post('user/login', 'UsersController#userLogin');
After adding the route to your routes.php, did you also change Form::open()? If not, you can just have your Form post to /login or /user/login.
Also, just because I'm a bit of a stickler for these sort of things, it's common practise to have controllers and models as singular, so UsersController would be UserController, and since the login function is within User(s)Controller, it doesn't need the user prefix. May help your code be more readable :)
Now in laravel 4 you can use this :
Route::post('/signup', array('before' => 'csrf', 'uses' => 'UsersController#userLogin'));

Resources