I'm trying the framework ZF2 and I try to do very independant modules like bundles in SF2.
I've got ZfcTwig to have Twig to render my views. This worked until I've created a second module.
-Application (default module)
-Admin
-view
index.twig
-layout
base.twig
-Blog
-view
index.twig
-layout
base.twig
The problem is that my Blog layout extend the Admin base layout then !
I've done my structure layout based on http://blog.evan.pro/module-specific-layouts-in-zend-framework-2
So in both Module.php I've this:
public function init($moduleManager)
{
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
$controller = $e->getTarget();
$controller->layout('layout/base.twig');
}, 100);
}
Plus I don't understand why I've to define twice the layout, one time in the init function of Module.php, the second on extend function of twig views.
For sure its work if I've different names.
And I see for this module: https://github.com/EvanDotPro/EdpModuleLayouts
But I think it should be possible without this to have really independant module since its the philosophy of the framework.
By default, ZfcTwig works in "zf way", using the two-step view pattern.
If you want to use the original twig system (for extends), you must specify it in your config file.
It is well commented :
/**
* If set to true disables ZF's notion of parent/child layouts in favor of
* Twig's inheritance model.
*/
'disable_zf_model' => true,
This way, you will control yous layouts with extends instructions.
Related
What is the best way to separate admin and front-end for a website in codeigniter where as I was to use all libraries, models, helpers etc. in common, but only controllers and Views will be separate.
I want a more proper way, up for performance, simplicity, and sharing models and libraries etc.
I highly suggest reading the methods outlined in this article by CI dev Phil Sturgeon:
http://philsturgeon.co.uk/blog/2009/07/Create-an-Admin-panel-with-CodeIgniter
My advice: Use modules for organizing your project.
https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/wiki/Home
Create a base controller for the front and/or backend. Something like this:
// core/MY_Controller.php
/**
* Base Controller
*
*/
class MY_Controller extends CI_Controller {
// or MX_Controller if you use HMVC, linked above
function __construct()
{
parent::__construct();
// Load shared resources here or in autoload.php
}
}
/**
* Back end Controller
*
*/
class Admin_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Check login, load back end dependencies
}
}
/**
* Default Front-end Controller
*
*/
class Public_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Load any front-end only dependencies
}
}
Back end controllers will extend Admin_Controller, and front end controllers will extend Public_Controller. The front end base controller is not really necessary, but there as an example, and can be useful. You can extend MY_Controller instead if you want.
Use URI routing where needed, and create separate controllers for your front end and back end. All helpers, classes, models etc. can be shared if both the front and back end controllers live in the same application.
I use a very simple approach: file folders. Check out the CI User Guide section, Organizing Your Controllers into Sub-folders.
I have my public-facing website built as any other would be built with CodeIgniter. Then I have two additional folders, controllers/admin and views/admin.
The admin controllers are accessed via http://[hostname]/admin/controller, and behave just as any other controller except they have specific authentication checks. Likewise, the views are simply called with the folder name included: $this->load->view('admin/theview');.
I haven't found a reason to do anything more complicated than that.
You all can find complete solution over here, https://github.com/bhuban/modular
Module separation for admin and front-end using HMVC and template separation using template libraries
I am using two third party libraries, you can find it in zip file.
HMVC for modular developed by wiredesignz
Template engine for templating by Phil Sturgeon
Just unzip it into your webserver root directory and run
localhost/modular for front-end
and
localhost/modular/admin for back-end
application/back-modules, it is for the back-end modules
application/front-modules, it is for the front-end modules
similarly
templates/admin for the back-end templates
templates/front for the front-end templates
themes/admin for the back-end themes
themes/front for the front-end themes
Nothing hacked in original code just configured using config.php and index.php
I'm starting to work with zend framework 1.12 and I ran into a little problem which I don't seem to be able to fix.
Up untill now i've done everything in the application, but now I want to build a module that handles all stuff that is related to settings.
Therefor i've created a new module and added a controller into it. This module automatically takes the layout from the application, which is what I want.
In this layout I use a view helper which works when I load a controller/action that is in the application folder. But when I try to load the layout around my controller inside my module the view helper is not available.
I hope I'm making sense and I would appreciate your help on this one!
Cheers!
If I understand you correctly you need to setup your view helper path in the bootstrap or application.ini, I do it in bootstrap:
protected function _initView()
{
//Initialize view
$view = new Zend_View();
//add custom view helper path
$view->addHelperPath('/../library/Namespace/View/Helper');
//do more stuff if needed
//add it to the view renderer
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer');
$viewRenderer->setView($view);
//Return it, so that it can be stored by the bootstrap
return $view;
}
also make sure your module includes it's own bootstrap file, this makes it possible to load resources to the module:
//at /application/modules/module/bootstrap.php
class Module_Bootstrap extends Zend_Application_Module_Bootstrap
{
//just an empty class is enough
}
hope this helps
I'm working on an Application, and most of the code will be returning in future project. So my idea was to create a structure such as this:
App/
- controllers
- models
- ...
Cake/
My_Custom_Folder/
- controllers
- models
- ..
Basically I want to add another folder next to the normal App folder and use App::build() to set the paths of the extra folder controllers, models, etc.
Now the goal is to only use the App layer when my project requires custom work, I have succeeded in that and CakePHP takes the controllers in the App over the ones in My_Custom_Folder if they are there.
For example: If i have a pages_controller.php in My_Custom_Folder AND one in my App folder, it will use the one in the App folder. If there is none in the App folder, then it uses the one in My_Custom_Folder.
However that is not how I want it to be working, what I want to do is extend the controllers from My_Custom_Folder so I can override methods and/or add new ones.
So far I have tried the following:
/My_Custom_Folder/pages_controller.php
Class PagesController Extends AppController {
Public $name = 'Pages';
Public Function home(){
echo 'default home';
}
}
/App/pages_controller.php
require_once(ROOT . DS . 'My_Custom_Folder' . DS . 'controllers' . DS . 'pages_controller.php');
Class AppPagesController Extends PagesController {
Public Function home(){
echo 'Override default home';
}
}
Unfortunately this doesn't work, it still loads the default home. Basically what i want is for it to load all methods from the My_Custom_Folder and allow the App folder to override methods and/or add methods the same way as you would by extending the Appcontroller. It does load both files, but it's not overriding any functions.
A structure like this would be great to maintain the same code over many projects and allow me to easily add new functionality for all projects by just updating the My_Custom_Folder and it would not break projects that have some customized code.
Any help on this would be greatly appreciated.
Take a look at plugin or behaviors or components or helpers. With plugins you can put them in one common folder for all apps (just like your My_Custom_Folder).
First, some context:
I am currently working on a modular Zend Framework application using Zend_Application. I wrote a custom module bootstrap that inserts custom resources into the Module Resource Autoloader, for example a 'Widget' resource.
Now, assuming the following structure:
/application
/application/modules/foo/widget/Bar.php
/application/modules/baz/widget/Qux.php
How would I be able to retrieve a list of every available widget in my application, preferably without traversing my entire directory structure?
Unfortunately I don't think there's a perfect solution to this. The best way I think is to have a standard way of 'registering' widgets in the respective module bootstraps, similar to how module-specific view helpers work.
Create a class for managing widgets which you instantiate in your main application bootstrap:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initWidgets()
{
return new Yourapp_Widgets();
}
}
and then in each module:
class Foo_Boostrap extends Zend_Application_Module_Bootstrap
{
protected function _initWidgets()
{
$widgetManager = $this->getApplication()->getResource('widgets');
$widgetManager->registerWidget('Foo_Bar');
}
}
you could then have a method on the widget manager class to return all registered widgets.
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'
),
),
);