I have an extension yii2-admin for RBAC, and I would like to add to this extension another controllers, views, models etc. Because in this module I would like to keep all operations who admin like CRUD for User table and for another.
What is the right way to add it? Because to add custom file in folder vendor it's bad way.
If you are using a module for manage the authorization control you can do this way
assuming you module is name auth
in you config/main.php you assign the module for auth
'modules' => [
.....
'auth'=> [ // your module for authorization (rbac)
'class' => 'vendor\your_vendor_name\auth\Module',
],
then in vendor\your_vendor_name\auth\Module.php
you should have this code for set the controllerNamespace for all the controller related to auth module
namespace vendor\your_vendor_name\auth;
use \yii\base\Module as BaseModule;
/**
* This is the main module class for the auth .
*
*
*
*/
class Module extends BaseModule
{
public $controllerNamespace = 'vendor\your_vendor_name\auth\controllers';
const VERSION = '1.0.0-dev';
public function init()
{
parent::init();
// custom initialization code goes here
}
}
at this point you can add all the controller you need in
`vendor\your_vendor_name\auth\controllers\`
and model in
`vendor\your_vendor_name\auth\models\`
and views
in
`vendor\your_vendor_name\auth\views\`
eg: for controller in vendor\your_vendor_name\auth\controllers\ i have
AuthAssignmentController.php
AuthItemChildController.php
AuthItemController.php
AuthRuleController.php
DefaultController.php
each of this manage the CRUD for the related model
Related
I am using CAKEPHP for creating my Application apis,
Currently I have few controllers in `
app/controllers/{UsersController, AdminController, StoresController}
` etc
I am accessing my controllers as //users/
However I want to add versioning system in cakephp
Something like
<ip>/<foldername>/v1/users/<action>
<ip>/<foldername>/v2/users/<action>
I tried creating a Folder inside Controllers/ as Controllers/v1/UsersController.php
However I am unable to access it.
How can i configure my routes
I'm quite confused about CakePHP version you are using (you tagged cakephp-3.0, and folder structure you used in question resembles that of 2.x), but both 2.x and 3.x versions have common concept called Prefix Routing, which is what you should use here. Below example assumes CakePHP 3.x:
You need to create directories (v1, v2) inside your Controller directory. Next, create individual controllers in that folder, remembering that namespace should also reflect this structure:
<?php
namespace App\Controller\v1;
use App\Controller\AppController;
class UsersController extends AppController {
//...
}
Final step is to configure routing in your routes.php. Example below:
Router::prefix("v1", function (RouteBuilder $routes){
$routes->fallbacks(DashedRoute::class);
});
More info can be found here:
Prefix Routing
For CakePHP 2.x things are little different:
In v2.x, you should NOT create folders inside Controller directory. All prefixed and unprefixed functions will reside in single controllers, eg.
class UsersController extends AppController {
/**
* Unprefixed function
*/
public function login(){
}
/**
* Prefix v1
*/
public function v1_login(){
}
/**
* Prefix v2
*/
public function v2_login(){
}
}
Next, you need to configure these prefixes in your app/Config/core.php file like so:
Configure::write('Routing.prefixes', array('v1', 'v2'));
After this, you should be able to access your actions with v1 and v2 prefixes, eg yourapp/v1/users/login will map to UsersController::v1_login() and yourapp/v2/users/login to UsersController::v2_login().
More info in documentation for 2.x: Prefix Routing v2.x
I am doing some refactoring of our large work app. This involves separating out some tools I've build, like a schema/seed migration tool for the command line, in to their own repositories to be used by multiple applications.
If it's in console/controllers, it gets picked up. If I move them to their own repository and require it via Composer, how do I get Yii to know when I say php yii db/up, i mean go to the new\vendor\namespace\DbController#actionup ?
If you create an extension (and load it through composer of course), you can locate Module.php inside, which will hold path to console controllers (that you can call with your terminal).
I will write my example for common\modules\commander namespace, for vendor extension your namespace will differ, but it work for all of them the same way.
So I have the following file structure for my extension
<app>
common
modules
commander
controllers
• TestController.php
• Module.php
My Module class looks as follow:
namespace common\modules\commander;
use yii\base\Module as BaseModule;
class Module extends BaseModule
{
public $controllerNamespace = 'common\modules\commander\controllers';
public function init()
{
parent::init();
}
}
And TestController.php is inherited from yii\console\Controller:
namespace common\modules\commander\controllers;
use yii\console\Controller;
class TestController extends Controller
{
public function actionIndex()
{
echo 123;
}
}
And the main part to make everything work is to register out Module.php in console/config/main.php settings
'modules' => [
'commander' => [
'class' => \common\modules\commander\Module::className(),
],
...
],
Here it is, now you can use your command like:
yii commander/test/index
And it'll print you 123, showing that everything works and Console Controllers are located in different folders!
I have created and configured a module fooModule. I need to create a component inside the module.
This is my configuration for my module in main.php
'modules'=>array(
'fooModule'=>array(
'class' => 'app\modules\fooModule\Module',
'components'=>array(
'testComponent'=>array(
'class'=>'app\modules\fooModule\components\testComponent',
),
),
),
),
In the folder module fooModule i have created a folder components with a file testComponent.php
TestComponet.php has a class test which extend \yii\base\Component. See below
namespace app\modules\fooModule\component;
class test extends \yii\base\Component {
public function __construct() {
private $bar;
}
public function exampleFunction() {
echo 'am alive, come and look for me please!!';
}
}
How do i access test class in fooModule Controller ?
Use Yii::$app->getModule('fooModule')->testComponent->exampleFunction(); for access module component.
The most elegant way to access module component from module controller without hardcoding module's ID is as follows:
$this->module->testComponent->exampleFunction();
This looks very elegant
Module::getInstance()->testComponent
I would like to divide my application in modules. For instance, there would be a "core" modules that contains the basic login functionality, app layout/formatting (CSS etc), user management and a diary.
Later on I may create other modules like a contact manager that can easily be added or removed from the application.
There would be some logic in the apps navigation for determining which modules are present and to show/hide the links to them.
How can I do this in terms of directory structure, namespaces and anything else that's needed?
I am looking at creolab/laravel-modules but it states that it is for Laravel 4. Can I still use it with 5 in exactly the same way?
The documentation says to place models, controllers and views within each module directory, but how does this work with routes? Ideally I would like each module to have its own routes.php file. How will all of this work with the stuff in the http and the resources directory?
I was thinking of something like this:
But I have no idea how I would get it to work.
I have just tried the tutorial here:
http://creolab.hr/2013/05/modules-in-laravel-4/
With no extra libraries etc, just pure Laravel 5.
I seem to have hit a brick wall with an error message:
FatalErrorException in ServiceProvider.php line 16:
Call to undefined method Illuminate\Config\Repository::package()
Regarding the following:
<?php namespace App\Modules;
abstract class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function boot()
{
if ($module = $this->getModule(func_get_args())) {
$this->package('app/' . $module, $module, app_path() . '/modules/' . $module);
}
}
public function register()
{
if ($module = $this->getModule(func_get_args())) {
$this->app['config']->package('app/' . $module, app_path() . '/modules/' . $module . '/config');
// Add routes
$routes = app_path() . '/modules/' . $module . '/routes.php';
if (file_exists($routes)) require $routes;
}
}
public function getModule($args)
{
$module = (isset($args[0]) and is_string($args[0])) ? $args[0] : null;
return $module;
}
}
What is causing this and how can I fix it?
Got my head around this a bit more now. Got my package/module routes and views working which is great:
abstract class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function boot()
{
if ($module = $this->getModule(func_get_args())) {
include __DIR__.'/'.$module.'/routes.php';
}
$this->loadViewsFrom(__DIR__.'/'.$module.'/Views', 'core');
}
public function register()
{
if ($module = $this->getModule(func_get_args())) {
}
}
public function getModule($args)
{
$module = (isset($args[0]) and is_string($args[0])) ? $args[0] : null;
return $module;
}
}
I have one last question, how would I load all my controllers from inside my package, much like how the loadViewsFrom() method works?
I seem to have figured it all out.
I'll post it here in case it helps other beginners, it was just about getting the namespaces right.
In my composer.json I have:
...
"autoload": {
"classmap": [
"database",
"app/Modules"
],
"psr-4": {
"App\\": "app/",
"Modules\\": "Modules/"
}
}
My directory and files ended up like this:
I got my Core module router.php to work by wrapping my controllers for that module in a group specifying the namespace:
Route::group(array('namespace' => 'Modules\Core'), function() {
Route::get('/test', ['uses' => 'TestController#index']);
});
I imagine when I come to doing my models for the package it will be a similar case of getting the namespaces right.
Thanks for all your help and patience!
Solution:
Step1: Create Folder “Modules” inside “app/”
Step2: In Modules folder create your Module (Module1( suppose admin Module))
Inside admin module : create the following folder
1. Controllers (here will your controller files)
2. Views (here will your View files)
3. Models (here will your Model files)
4. routes.php (here will your route code in this file)
Similarly, you can create multiple modules
Module2( suppose API )
-Controllers
-Views
-Models
-routes.php
Step3 : Create ModulesServiceProvider.php inside “Modules/” Folder
Step4 : Paste following code inside ModulesServiceProvider.php
<?php
namespace App\Modules;
/**
* ServiceProvider
*
* The service provider for the modules. After being registered
* it will make sure that each of the modules are properly loaded
* i.e. with their routes, views etc.
*
* #author kundan Roy <query#programmerlab.com>
* #package App\Modules
*/
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class ModulesServiceProvider extends ServiceProvider {
/**
* Will make sure that the required modules have been fully loaded
*
* #return void routeModule
*/
public function boot() {
// For each of the registered modules, include their routes and Views
$modules=config("module.modules");
while (list(,$module)=each($modules)) {
// Load the routes for each of the modules
if (file_exists(DIR.'/'.$module.'/routes.php')) {
include DIR.'/'.$module.'/routes.php';
}
if (is_dir(DIR.'/'.$module.'/Views')) {
$this->loadViewsFrom(DIR.'/'.$module.'/Views',$module);
}
}
}
public function register() { }
}
Step5 : Add following line inside ‘config/app.php’ file
App\Modules\ModulesServiceProvider::class,
Step6 : Create module.php file inside ‘config’ folder
Step7 : Add following code inside module.php (path =>
“config/module.php”)
<?php
return [
'modules'=>[
'admin',
'web',
'api'
]
];
Note : You can add your module name whichever you have created. Here there are modules.
Step8 : Run this command
composer dump-autoload
A little late, but if you want to use modules in your future projects, i've written a module generator. It generates modules via php artisan make:module name You can also just drop some modules in the app/Modules folder and they are ready to use/work.
Take a look. Save some time ;)
l5-modular
You can also use pingpong-labs
documentations Here.
Here is an example.
You can just install and check the process.
Note: I am not advertising. Just checked that cms built on Laravel with module support. So thought that might be helpful for you and others.
Kundan roy: I liked your solution but I copied your code from StackOverflow, I had to change the quotes and semi-quotes to get it working - I think SOF replace these. Also changed Dir for base_path() to be more inline with Laravel's (new) format.
namespace App\Modules;
/**
* ServiceProvider
*
* The service provider for the modules. After being registered
* it will make sure that each of the modules are properly loaded
* i.e. with their routes, views etc.
*
* #author kundan Roy <query#programmerlab.com>
* #package App\Modules
*/
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class ModulesServiceProvider extends ServiceProvider
{
/**
* Will make sure that the required modules have been fully loaded
* #return void routeModule
*/
public function boot()
{
// For each of the registered modules, include their routes and Views
$modules = config("module.modules");
while (list(,$module) = each($modules)) {
// Load the routes for each of the modules
if(file_exists(base_path('app/Modules/'.$module.'/routes.php'))) {
include base_path('app/Modules/'.$module.'/routes.php');
}
// Load the views
if(is_dir(base_path('app/Modules/'.$module.'/Views'))) {
$this->loadViewsFrom(base_path('app/Modules/'.$module.'/Views'), $module);
}
}
}
public function register() {}
}
pingpong/modules is a laravel package which created to manage your large laravel app using modules. Module is like a laravel package for easy structure, it have some views, controllers or models.
It's working in both Laravel 4 and Laravel 5.
To install through composer, simply put the following in your composer.json file:
{
"require": {
"pingpong/modules": "~2.1"
}
}
And then run composer install to fetch the package.
To create a new module you can simply run :
php artisan module:make <module-name>
- Required. The name of module will be created.
Create a new module
php artisan module:make Blog
Create multiple modules
php artisan module:make Blog User Auth
for more visit: https://github.com/pingpong-labs/modules
I am working on implementing Zend Framework within an existing project that has a public marketing area, a private members area, an administration site, and a marketing campaign management site. Currently these are poorly organized with the controller scripts for the marketing area and the members area all being under the root of the site and then a separate folder for admin and another folder for the marketing campaign site.
In implementing the Zend Framework, I would like to create be able to split the controllers and views into modules (one for the members area, one for the public marketing area, one for the admin site, and one for the marketing campaign admin site) but I need to be able to point each module to the same model's since all three components work on the same database and on the same business objects.
However, I haven't been able to find any information on how to do this in the documentation. Can anyone help with either a link on how to do this or some simple instructions on how to accomplish it?
What I do is keep common classes in a "library" directory outside of the modules hierarchy. Then set my INCLUDE_PATH to use the "models" directory of the respective module, plus the common "library" directory.
docroot/
index.php
application/
library/ <-- common classes go here
default/
controllers/
models/
views/
members/
controllers/
models/
views/
admin/
controllers/
models/
views/
. . .
In my bootstrap script, I'd add "application/library/" to the INCLUDE_PATH. Then in each controller's init() function, I'd add that module's "models/" directory to the INCLUDE_PATH.
edit: Functions like setControllerDirectory() and setModuleDirectory() don't add the respective models directories to the INCLUDE_PATH. You have to do this yourself in any case. Here's one example of how to do it:
$app = APPLICATION_HOME; // you should define this in your bootstrap
$d = DIRECTORY_SEPARATOR;
$module = $this->_request->getModuleName(); // available after routing
set_include_path(
join(PATH_SEPARATOR,
array(
"$app{$d}library",
"$app{$d}$module{$d}models",
get_include_path()
)
)
);
You could add the "library" to your path in the bootstrap, but you can't add the "models" directory for the correct module in the bootstrap, because the module depends on routing. Some people do this in the init() method of their controllers, and some people write a plugin for the ActionController's preDispatch hook to set the INCLUDE_PATH.
This can also be accomplished through a naming convention to follow Zend_Loader. Keep your model files in the models folder under their module folder. Name them as Module_Models_ModelName and save them in a file name ModelName.php in the models folder for that module. Make sure the application folder is in your include path and assuming you are using Zend_Loader for auto loading, you can then just reference the models by their class name.
This has the advantage of keeping your model code grouped in with the actual module it is for. This keeps the module contained within a single folder structure which helps encourage encapsulation. This will also help in the future if you need to port the module to another project.
I just built this custom Action Helper for the problem you describe:
<?php
class My_Controller_Action_Helper_GetModel extends Zend_Controller_Action_Helper_Abstract
{
/**
* #var Zend_Loader_PluginLoader
*/
protected $_loader;
/**
* Initialize plugin loader for models
*
* #return void
*/
public function __construct()
{
// Get all models across all modules
$front = Zend_Controller_Front::getInstance();
$curModule = $front->getRequest()->getModuleName();
// Get all module names, move default and current module to
// back of the list so their models get precedence
$modules = array_diff(
array_keys($front->getDispatcher()->getControllerDirectory()),
array('default', $curModule)
);
$modules[] = 'default';
if ($curModule != 'default') {
$modules[] = $curModule;
}
// Generate namespaces and paths for plugin loader
$pluginPaths = array();
foreach($modules as $module) {
$pluginPaths[ucwords($module)] = $front->getModuleDirectory($module) . '/models';
}
// Load paths
$this->_loader = new Zend_Loader_PluginLoader($pluginPaths);
}
/**
* Load a model class and return an object instance
*
* #param string $model
* #return object
*/
public function getModel($model)
{
$class = $this->_loader->load($model);
return new $class;
}
/**
* Proxy to getModel()
*
* #param string $model
* #return object
*/
public function direct($model)
{
return $this->getModel($model);
}
}
So in your Bootstrap.php:
Zend_Controller_Action_HelperBroker::addPrefix('My_Controller_Action_Helper');
And in any of your controllers:
<?php
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$model = $this->_helper->getModel('SomeModel');
}
}
And this will allow your access to models in any controller across all modules.
I'm having the same problem.
Bill's answer doesn't fit for me - cos i tend to divide my modules, not by 'who is seeing them', but by 'what they do'. E.g a 'forum module' might be managed by both admin and public.
I'm trying to have front end modules, like admin, members , public - but these then use other modules like 'forum/validatepost', 'forum/show users personal info'.
If anyone could shed light on how they protect a back-end module from the public , then that would be handy. I guess ACL may be the key but it still makes me nervous having access controlled by objects as opposed 'file system/.htaccess' etc.
To answer PHPoet's question :
(i) Paths to module's controller directories can be specified by calls to front controller:
e.g see : "12.11.2. Specifying Module Controller Directories" (Zend Framework Docs)
(ii) Paths to views can be set using ViewRenderer (Controller Action Helper)
e.g. see: 'Example 12.12. Choosing a Different View Script' (Zend Framework Docs)
By playing around its possible to alter the default paths to views and controllers, thus freeing up your autoloader to run as normal.
(I have not looked into the way autoloader works, but it would make sense for it to have some mapper system to solve this kind of issue.)
<?php
return array(
'modules' => array(
'Application',
'DoctrineModule',
'DoctrineORMModule',
'Merchant',
),
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'./module',
'../vendor',
// 'here we can load module'
'comomonmodule'
),
),
);