I had to develop a CMS using Zend Framework and I used the default namespace defined in my boostrap for my backend:
autoloaderNamespaces[] = "Application_"
Now I want to develop the frontend, but I don't know how to do it, since I have access to my backend from the /public/ directory.
Then I would like to use a different layout for my frontend than the one I use for the backend access. So I found this post but I don't know if I have to change/add (and then how to change) the module of my backend, or if I have to create a second module that I will use for my frontend
my file tree is like this :
So if I create a frontend module, shall I create a frontend directory next to the applicationdirectory ?
EDIT : I created 2directories pub and frontend next to the application directory. In pub/index.php I instanciated the bootstrap with the application/configs/application.ini file with a different APPLICATION_FRONT_ENV :
[frontprod : production]
bootstrap.path = APPLICATION_FRONT_PATH "/bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_FRONT_PATH "/controllers"
autoloaderNamespaces[] = "Frontend_"
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_FRONT_PATH "/layouts/scripts"
[frontdev: frontprod]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1
and in the frontend/bootstrap.php I loaded models from applicationdirectory :
public function _initAutoloader(){
$baseAutoload = new Zend_Loader_Autoloader_Resource(array(
'namespace' => 'Application',
'basePath' => realpath(dirname(__FILE__).'/../application')
)
);
}
And it seems to be working fine =)
thank you !
In Zend Framework you can organise your app in modules, wich suits very well to your needs. Unfortunately the doc doesn't emphasize enough the importance of this concept, and how you should implement it from day one.
Modules allows you to regroup under a same module folder everything that is related to this module only, and this way to isolate "parts" of your app in logical groups.
In your case it would be "back" and "front", but you could also have a "forum" module or let's say a "shop" module.
In the urls point of view, the default routing of a modular structure is example.com/module/controller/action, but using hostname routes you can also have www.example.com pointing to your "front" module and admin.example.com pointing to your backend.
Have a look at the poor documentation section about modules, and don't panic, you won't have to rename everything if you move your current controllers, views and models in the "default" module.
There is an other alternative that could suit well for a backend/frontend logic, but not if you want to split your code in more logical parts (forum, blog, shop,...). You just create a second application folder (you would name 'frontend') next to the 'application' folder, and a second public directory (where you can symlink your assets folder if you use the sames), and a different namespace.
To be able to autoload your 'Application_' classes in your frontend code, just add and configure a Module Autoloader in your frontend bootstrap. The code is quite simple :
//in your frontend/Bootstrap.php
public function _initAutoloader(){
new Zend_Loader_Autoloader_Resource( array(
'namespace' => 'Application_',
'path' => realpath(dirname(__FILE__).'/../application'
)
);
}
For the application.ini config file i would recommend, instead of duplicating it, that you create a section [frontprod : production] section where you override your backend settings (and a matching [frontdev: frontprod] for your local settings).
I hope this helped. There is so much to say about all the topics introduced here that you should first have a look at this, then comment this answer with more specific questions about the problems you may encounter, and i'll extend the answer.
Related
I have to make a webapplication with many different modules (like a todo-module, document-modules, and a big usermanagement-module for admin users). The total number of pages is > 100. And the module access is different for each user.
I am working with Laravel and Vue-router.
But what is the best practice to do it?
Create a SPA-application, with 1 large vue-router for everything?
For every module a own single "SPA" (with and own vue-router)?
Or another suggestion...?
Little late but I will try to answer the question. This is more an architectural question than just routing level question.
TLDR: You will need a mix of approaches. One approach won't fit.
1. Routing Mode
First, you should determine if you are going with HTML 5 history mode or hash mode
It is 2018, and I definitely recommend that you use HTML5 history mode.
If you use history mode, then it means your client-side router will need to work in sync with your server-side router.
2. Micro-frontends
I am not sure if you know this, but micro-frontends is the term you are looking for. Basically, it is your first line of segregation. You should split your app into multiple smaller apps. Each app will have its root component, router, models, services, etc. You will share many of the components (Of course, word very large application is important. And I literally mean it.)
3. Mono-repo considerations
If you have chosen to go ahead with Micro-frontends, then you might consider mono-repo setup
using Lerna or Builder.
4. Routing Module - Initialization
Irrespective of micro-apps, your app should have one starting point - main.js or index.js. In this file, you should initialize all your singleton things. Main singleton entities in a typical Vue.js app are Root Component, Data Store, Router, etc.
Your routing module will be separate from any component. Import routing module in this entry file and initialize it here.
5. Routing Module - Implementation
Routing module should be further split into smaller modules. Use simple functions and ES modules to do that. Each function will be responsible for returning a RouteConfig object. This is how it will look:
const route: RouteConfig = {
path: '/some-path',
component: AppComponent,
children: [
getWelcomeRoute(),
getDashboardRoute()
]
};
function getWelcomeRoute(): RouteConfig {
return {
name: ROUTE_WELCOME,
path: '',
component: WelcomeComponent
};
}
At route level, you should consider doing lazy loading of the modules. This will save many bytes from loading upfront:
function getLazyWelcomeRoute(): RouteConfig {
// IMPORTANT for lazy loading
const LazyWelcomeComponent = () => import('views/WelcomeComponent.vue');
return {
name: ROUTE_WELCOME,
path: '',
component: LazyWelcomeComponent
};
}
You cannot do this unless you use bundler like Webpack or Rollup.
5. Routing Module - Guard
This is very important
Guards are where you should handle your authorization. With Vue.js, it is possible to write component level route guard. But my suggestion is to refrain from doing so. Do it only when absolutely necessary. It is basically a separation of concern. Your routing module should possess the knowledge of authorization of your app. And technically, authorization exists/applies to a route than a component. That is the reason, why we created routing as a separate module altogether.
I am assuming that you are using some sort of data store like Redux or Vuex for the very large application. If you are going to write route level guards, then you will need to consult with data from Redux/Vuex store to take authorization decisions. It means you need to inject store into routing module. The simplest way to do that is to wrap your router initialization into a function like this:
export function makeRouter(store: Store<AppState>): VueRouter {
// Now you can access store here
return new VueRouter({
mode: 'history',
routes: [
getWelcomeRoute(store),
]
});
}
Now you can simply call this function from your entry-point file.
6. Routing Module - Default route
Remember to define a default catch-all route to show generic/intelligent 404 message to your users.
7. Routing Module - Routing data
Since we are really talking about very large application, it is better to avoid direct access to a router within your component. Instead, keep your router data in sync with your data store like vuex-router-sync
. You will save the painful amount of bugs by doing this.
8. Routing Module - Side effects
You will often use $router.replace() or $router.push() within your components. From a component perspective, it is a side effect. Instead, handle programmatic router navigation outside of your component. Create a central place for all router navigation. Dispatch a request/action to this external entity to handle these side effects for you. TLDR; Don't do routing side effect directly within your components. It will make your components SOLID and easy to test. In our case, we use redux-observable to handle routing side effects.
I hope this covers all the aspects of routing for a very large scale application.
If you go with SPA app, please make sure you are using these practices:
Lazy loading/async components. We usually do lazy loading for static assets. In the same spirit, we only need to load the components when the routes are visited. Vue will only trigger the factory function when the component needs to be rendered and will cache the result for future re-renders.
import MainPage from './routes/MainPage.vue'
const Page1 = r => require.ensure([], () => r(require('./routes/Page1.vue')))
const routes = [
{ path: '/main', component: MainPage },
{ path: '/page1', component: Page1 }
]
Combining routes: (related to above) For example, in the following case, 2 routes are output in the same chunk and bundle, causing that bundle to be lazy-loaded when either route is accessed.
const Page1 = r => require.ensure([], () => r(require('./routes/Page1.vue')), 'big-pages')
const Page2 = r => require.ensure([], () => r(require('./routes/Page2.vue')), 'big-pages')
Nuxt can help you with that. It generates your folder Structur dynamically to a router config file. Have a look at https://nuxtjs.org/guide/routing
It has even more help functions than routing. But especially for large applications in general an idea to set on nuxt
I'm working with reusable modules in Zend2 and I have a little problem which concerns code duplication.
I have an User module, which has i.e an HTML template register (template path: user/user/register).
It contains some basic HTML but in one of my projects, I need to embed this template with a < div > for CSS stylization (the rest of the HTML page doesn't change).
After the User module, I load my Application module where I can overwrite the user/user/register template and put new code but I'm unable to render the original user/user/register template through it.
Example of code in Application module -> user/user/register:
<div><?=$this->render('user/user/register')?></div>
This causes an endless loop and I don't want to copy/paste all the HTML from my user/user/register template in User module.
Anyone can help me ?
Thank you !
What you're trying to achieve won't work. You can not have two templates with identical names. The Module that loads the key the latest will always have priority.
You have to understand that templates are just a key inside a big array.
'view_manager' => array(
'template_map' => array(
'layout/layout' => 'my\layout.phtml'
)
)
So if you have two modules providing this configuration, it doesn't change the fact that both use the key layout/layout. Therefore whatever Module loads later, wins.
TL/DR You can only overwrite templates, not extend them. In your case you have to create a separate 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.
I'm creating a widget where there will be 2 types of params:
-The one that can change depending on where we call the widget, those one will be defined in the widget call:
<?php $this->widget('ext.myWidget', array(
'someParams' => 'someValues',
)); ?>
-The one that are the same for all the call to the widget (a path to a library, a place to save an image, ...)
I would like to know what is the best way to define the second type of parameters.
I'm hesitating between making the user define it in the params array in the config file or defining it in an array in the Widget file.
The main advantage of the first option is that the user won't have to modify the Widget file so in case of update his modifications won't be overwritten, but this is not a specific user params so putting it in the parmas array in config file might seem strange.
So what would be the best solution? If there is another one better thant the 2 above please tell me!
Edit:
To clarify my thought:
My widget will generate some images that can be stored in a configurable directory. But since this directory has to be the same each time the widget is called I don't see the point of putting this configuration into the widget call!
This is why I was thinking about putting some params into the config file, in the params array like:
params => array(
'myWidget' => array(
'imageDir' => 'images',
)
)
But I don't know if it is a good practice that an extension has some configuration values in the params array.
Another solution would be to have a config.php file in my extension directory where the user can set his own values so he won't have to modify his main config file for the plugin. But the main drawback of this alternative is that if the user update the extension, he'll loose his configuration.
This is why I'm looking for the best practice concerning the configuration of a widget
Maybe what your looking for is more of an application component than a widget. You've got a lot more power within a component that you have with a widget. It can all still live in your extensions directory, under a folder with all the relevant files, and still be easily called from anywhere but the configuration can then be defined in configuration files for each environment.
When your setting the component in your configs, just point the class array parameter to the extensions folder, instead of the components folder.
Update:
If you do want to use a widget because there's not a lot more complexity, you can provide some defaults within application configurations for widgets I believe, I've never used it myself, see here: http://www.yiiframework.com/doc/guide/1.1/en/topics.theming#customizing-widgets-globally.
But I've found with more complex widgets that a component serves me better in the long run as I can call methods and retrieve options on it much easier and cleaner, but still have everything related to the extension within one folder.
As I read the doc, controllers in CodeIgniter are supposed to support multiple level subfolders, but as far as I have tested, it is impossible to work after first a first level folder.
By example:
mysite.dev/ (index page, default controller home.php, works)
mysite.dev/admin/ (admin section, in admin/home.php, works)
mysite.dev/admin/manage/ (in admin/manage/home.php, do not work)
I am trying to know why and how to make it work on multiple level sub folders?
Thanks in advance!
CI only allows one sub-dir level. However, you can emulate this pattern with routes file as #Brendan says:
Controllers:
welcome.php
admin/admin.php
admin/manage.php
Routes file:
$route['admin/manage/:any'] = "admin/manage/$1";
$route['admin/admin'] = 'admin/home.php';
You can implement some changes to the hardcode to get works as expected: http://codeigniter.com/forums/viewthread/190563/