Laravel shared project codebase - laravel

I've searched a few days now and I don't think I've found a relevant question anywhere.
Is there a way to have multiple "sub-projects/sites" which use a shared codebase for their controllers and models, but have their own routes and views.
For example there would be: public/site1 and public/site2 with their own /views, /routes folder and own .env but would both use the same /app code.
These sub-projects would be all on the same server, so if there would be an other solution where there would be multiple applications which can link controllers and models from 1 main "core" application would be possible too.
EDIT: I'm looking more if there is a way to autoload for example models and controllers from an other location on the server, that way whenever I update the "core" once it gets used on all sub-projects.

You can create directories and namespaces for each subsite you want with a structure like this for example.
app
Http (for shared controllers)
Models (for shared models)
site1
Http
Models
site2
Http
Models
routes
shared.php
site1.php
site2.php
You would need to register them in the composer.json like:
"autoload": {
"psr-4": {
"App\\Shared\\": "app/",
"App\\Site1\\": "site1/",
"App\\Site2\\": "site2/"
}
},
In the RouteServiceProvider you can route each route file using a different domain or subdomain and include the shared.php for each (for auth routes for example). It could look something like:
protected function mapSite1Routes()
{
Route::group([
'domain' => config('sites.site1.domain'),
'namespace' => $this->namespace,
'middleware' => ['web'],
], function () {
require base_path('routes/shared.php');
require base_path('routes/site1.php');
});
}
This way you have one application with shared and seperate sources.
That should get you started :)

I’ve actually done this myself. One my own projects is a multi-tenant content management system. There’s the core CMS codebase, but then for each “tenant” I create a package that contains that tenant’s routes, views, resources etc.
Each package is included via Composer and just has the same directories as any other Laravel project:
/public
/css
/img
/js
/resources
/assets
/sass
/views
/routes
web.php
/src
/Console
/Commands
/Http
/Controllers
PackageNameServiceProvider.php
The service provider class is a bit “hack-y” though. I have to do something like this:
class PackageNameServiceProvider extends ServiceProvider
{
public function boot()
{
if ($this->app->runningInConsole()) {
$this->defineAssetPublishing();
$this->defineConsoleCommands();
}
if ($this->app->make(Tenant::class)->name == 'This Tenant') {
$this->defineRoutes();
$this->defineResources();
}
}
}
It would be nice if I could get rid of the if ($this->app->make(Tenant::class)->name == 'This Tenant') bit. However, it’s working alright for me so far.

Related

Managing Multiple API versions in Laravel

I'm working on exposing an API using one base URL (e.g. https://api.domain.com) and having that URL handle all versions of the API (the API consumer will need to send Accept-Version in the request header to indicate which version of the API they're trying to use).
How would I manage this approach in Laravel?
I was thinking that I could put all of my controllers, helpers, models, routes, config, etc. in a, say, 1.0.0 folder and use those for version 1 of my API. When I release a new version, maybe I make copies of the original code, put them in a 1.1.0 folder, and make changes there.
If I were to use this folder approach, what would I need to do in the routes to indicate which folder to use? How would my controllers know what models, helpers, config, etc. to use? Feels like this approach could get very messy and convoluted.
In your RouteServiceProvider.php you can define the routes for the application. Here you can also define the namespace, name prefix, and middleware for the routes. Simply add a new route map for each version of your api. Have the middleware check the version, redirecting if necessary, and set the name prefix/namespace to the correct version directory.
the RouteServiceProvider would look something like:
protected function mapApi-1-0-0-Routes()
{
Route::middleware(['api', 'version'])
->name('1.0.0.')
->namespace('1.0.0')
->group(base_path('routes/api.php'));
}
then your middleware would look something like
public function handle($request, Closure $next)
{
switch ($request->version) {
case "1.0.0":
$route = $request->version.$request->route()->getName();
break;
// more versions
return redirect()->route($route)->with($request);
}
I haven't tested this.
Route group name prefixes:
https://laravel.com/docs/7.x/routing#route-group-name-prefixes
Route namespaces:
https://laravel.com/docs/7.x/routing#route-group-namespaces
Redirecting named routes:
https://laravel.com/docs/7.x/redirects#redirecting-named-routes
Global middleware:
https://laravel.com/docs/7.x/middleware#global-middleware
Writing service providers:
https://laravel.com/docs/7.x/providers#writing-service-providers

How to access a view in a laravel module with routes?

I'm currently working on my homework for school which i've read about Laravel modules and i'm currently working with this https://nwidart.com/laravel-modules package.
I've managed to create modules, migrations and models. now i want to access a module via a simple link from route. like this:
CRM
I've created 3 modules with core,crm and sell names. which base on information from internet, I've understand that i can access them with localhost/crm or sell or core. now how i can fix my problem?
I've also tried {{ route('core::index') }}. Thanks
Update 1: Views in every module are like this: Resources\views\index.blade.php if u look at above link u will see a example of what i've said.
Update 2: routes: Every module have 1 route when i create module with package.
Laravel root module routes\web :
Route::get('/', function () {
return view('welcome');
});
and CRM route module Modules\CRM\routes\web\ and rest are just like below with different names :
Route::prefix('core')->group(function() {
Route::get('/', 'CoreController#index');
});
route() helper is for named routes. You can use url() helper to match a uri, or you have to add a name to your route, like:
Route::prefix('core')->group(function() {
Route::get('/', 'CoreController#index')->name('core.index');
});
and then you can
CRM
try to set name for your route
https://laravel.com/docs/5.8/routing#named-routes
Route::prefix('core')->group(function() {
Route::get('/', 'CoreController#index')->name('crm.index');
});
and then this should work
CRM
In the latest version 6 i change the view resource config and read from modules folder like this :
'paths' => [
base_path('Modules/Duet/Resources/views'),
base_path('Modules/anotherModule/Resources/views'),
],
I use like this to address view page in module controller:
return view("module::pages.main");
module is your module name.

Laravel Route to Standalone WebApp

I am trying to build a portal in Laravel to serve some other, standalone web apps (not built in Laravel), but I am struggling to find out how to route to these apps if I want to place them outside the public folder.
In the past, I would use (temporary) symlinks for this kind of things, but I was wondering if Laravel provides another solution.
So, I have a folder:
module
module/index.php
module/js/whatever
module/css/whatever
module/img/whatever
and I want a route /modules/1 to link to index.php in the module-folder in such a way that the resources in this folder (js/css/img) are also accessible.
Any suggestions?
You can include other PHP files with require_once.
web.php
Route::any('/webapp/{assets?}', 'WebAppController#index');
WebAppController
class WebAppController {
public function index(Request $request) {
require_once '../module/index.php';
if ($request->assets) {
// check from session if user is logged in
// require asset as well
// (or download them https://laravel.com/docs/5.5/responses#file-downloads)
}
}
}
http://php.net/manual/en/function.require-once.php

Routing in Laravel module

I created a module in Laravel 5 i.e inside the same level as the app folder as part of making an HMVC structure in Laravel. I have two modules in the module folder, one being a project folder and another a form folder. Now I got the controller, model and view inside these folders.
Click here to view folder structure
Now when i try to access my controller like
Route::controller('project/dashboard', 'ProjectController#index');
I get error
ReflectionException in ControllerInspector.php line 35:
Class ProjectController does not exist
I would like to know about routing a controller in modular structure in Laravel.
When use Route::controller use this Route::controller('project/dashboard','ProjectController');
And inside your controller define methods like
public function getIndex(){
// write your code here
}
public function postIndex(){
// write your code here
}
public function getCreate(){
// write your code here
}
public function postStore(){
// write your code here
}
You are having that problem because that modules directory is not visible to Laravel's psr module. Based on laravel version what you can do is put your modules directory into psr in composer after "App\\": "app/",
Eg:
"psr-4": {
"App\\": "app/",
"Modules\\": "modules/"
}
in app.php which resides in either app/config/app.php or in config/app.php in laravel 5.
And then execute the composer command composer dump-autoload -o.
Here you go now your modules will work as you wished.
If still having trouble you can try this package which does the same thing you are trying to. https://github.com/yubarajshrestha/laravel-module

Why can't my class be found, when it's in the same namespace?

I have created a modules folder in my Laravel app. There are two modules so far, but I'm just concentrating on core here.
I'm using Confide and Entrust to build User functionality, like so:
namespace App\Modules\Core;
use Zizaco\Confide\ConfideUser;
use Zizaco\Entrust\HasRole;
class User extends ConfideUser {
use HasRole;
}
and Permissions:
namespace App\Modules\Core;
use Zizaco\Entrust\EntrustPermission;
class Permission extends EntrustPermission
{
}
and Roles:
namespace App\Modules\Core;
use Zizaco\Entrust\EntrustRole;
class Role extends EntrustRole
{
}
My Composer.json autoload reads:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/modules"
],
"psr-0": {
"App\\Modules\\": "modules/"
}
},
I put the psr-0 stuff in there because I couldn't get things to work. They still don't work, though the output autoload files when I run composer seem to have promising entries in them.
The database has been migrated, and now I'm trying to run the database seeding. My seeding script reads:
use App\Modules\Core\User;
use App\Modules\Core\Role;
use App\Modules\Core\Permission;
class UserTablesSeeder extends Seeder {
public function run()
{
DB::table('users')->insert(array(
'email' => 'xxx',
'first_name' => 'xxx',
'password' => 'xxxx',
'active' => 1
));
$admin = new Role;
$admin->name = 'Admin';
$admin->save();
$manageUsers = new Permission;
$manageUsers->name = 'manage_standard_users';
$manageUsers->display_name = 'Manage Users';
$manageUsers->save();
$admin->perms()->sync(array($manageUsers->id));
$user = User::where('email','=','xxx')->first();
$user->attachRole($admin);
}
}
But when I run php artisan db:seed I get an error:
PHP Fatal error: Class 'Permission' not found in /home/wedding/quincy/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 604
{"error":{"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","message":"Class 'Permission' not found","file":"\/home\/wedding\/quincy\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Eloquent\/Model.php","line":604}}
If I get rid of all the namespacing it all works just fine, but I think I should keep the namespaces because of the modularity I'm trying to create.
I've run composer dump-autoload, and install for when I added the psr-0 entry. So I'm not sure what else I need to do. I'm very new to composer, so at this point I'm lost as to what the problem is.
Thanks in advance.
Don't know if you found your answer.
I think you need to update your role and permission namespaced class names here:
File: vendor/entrust/config/config.php:
(Default is just "Role" and "Permission" without a namespace, so it doesn't work when you move your implementations into one).
You also have two other options:
add an alias for the fully namedspaced permission and role class on the app/config.php (Role => "Namespace").
there's a mechanism to override package config settings with appropriately named files. You can override just the two entries you need (the Role and Permission namespaces).
Confide and Entrust both are looking for Role and Permission model in global namespace. As you have changed namespace of both these models, Confide and Entrust are not able to find it. To solve this problem, you need to override Entrust configuration.
Create directory "app/config/packages/zizaco/entrust"
Copy file "vendor/zizaco/entrust/src/config/config.php" to "app/config/packages/zizaco/entrust/config.php"
Edit "app/config/packages/zizaco/entrust/config.php" and change following two lines
'role' => 'App\Modules\Core\Role',
'permission' => 'App\Modules\Core\Permission',
php artisan clear-compiled
php artisan optimize
You should rely on Laravel's packages (created thru Workbench, for instance) while developing localy.
Packages are the primary way of adding functionality to Laravel.
Workbench packages and their classes are handled automaticaly by Laravel - no need to configure anything.
More informations here: http://laravel.com/docs/packages
if you want to use your own modules instead of standard workbench packages, check out this article that depics how to achieve that:
http://creolab.hr/2013/05/modules-in-laravel-4/
summary by the author ( Boris Strahija ):
Laravel 4 is heavily based on composer packages, which is a good thing, but sometimes developers (like myself) like to separate their code into modules. This is especially nice when building larger projects. Now this was fairly easy to do in Laravel 3 with the bundles system, but in Laravel 4 many people just recommend building packages since L4 has a nice workbench feature. This is all good, but sometimes I like to separate my app specific controllers and views into modules, and not have to go through it with the workbench.
In short, you have to
put your modules code somwhere (for example /app/modules/)
include the directory in composer.json file, under autoload/classmap
create an appropriate service providers (Laravel 4 uses service providers to register and boot up the packages, you can use it with modules as well)
register the service providers - add them to app config in “app/config/app.php” under the providers array
So now we have out modules fully working. You can add module specific routes, group your controllers/views/models, get module configuration like this:
Config::get('content::channels');
Or get translated phrases like this:
Lang::get('shop::errors.no_items_in_cart');
Finally, to test your modules you can create some routes, but that is up to you how you use your code.
If you look at Doctrine composer.json, for example /vendor/doctrine/cache/composer.json:
"autoload": {
"psr-0": { "Doctrine\\Common\\Cache\\": "lib/" }
},
The files are located in:
/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php
/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php
... and so on
By that logic, I think you should put your files in:
modules/App/Modules/Core/User.php
modules/App/Modules/Core/Permission.php
modules/App/Modules/Core/Role.php
From you screenshot the Permission class is located in the models folder so when you include your namespace you should type
use App\Modules\Core\Models\Permission;

Resources