Zend Framework Controller to Module routing - zend-framework

So i have been doing my best trying to absorb as much as i can about the Zend Framework which is pretty new to me, i'm about two weeks in since my first attempts and being doing well so far.
However i have run into a small issue i just can't figure out.
So here's the deal, i have a standard Zend Framework project with a number of modules in it. Like this :
- Project
- - Application
- - - configs
- - - controllers
- - - - IndexController
- - - - WMSController
- - - forms
- - - layouts
- - - models
- - - modules
- - - - content
- - - - - controllers
- - - - - - IndexController
- - - - - models
- - - - - views
- - - - - Bootstrap
- - - views
- - - bootstrap
- - public
etc..
Now i have a simple test link set in the view for the WMSController wich is supposed to direct someone klicking it to the IndexController of the content module.
test link to content module
Now as you can probably see this link is NOT going to work since it is pointing towards localhost/wms/content which would be the content action in the WMSController which doesn't exist at this moment.
Now what i want to do is to make the wms/content actually point towards the IndexController of the content module. Why? Well i simply do not want a user to type localhost/content to get to the content module which is part of the WMS. I want to force them to get trough the WMS controller first.
I have read numerous things about routing being the solution using the bootstrap or the autoloader but pretty much all of them simply help you with pointing a certain url to a specific action in a specific controller.
What i want is a url to point to a specific action in a specific controller in a specific module.
NOTE: All the other controllers and views are still the default generated versions with no changes made to them yet!
If anyone could show me a code example of how this is done it would be much appreciated!

If I understand correctly you simply want /wms/content to point to module content controller Index action index. This is a case where a simple router will work(at least until you want to get more complex)
In your application.ini add these lines:
resources.router.routes.content.route = "wms/content"
resources.router.routes.content.defaults.module = "content"
resources.router.routes.content.defaults.controller = "index"
resources.router.routes.content.defaults.action = "index"
this is the easiest way to build a custom route.
*Note:*The 4th parameter from the left is the name of the route, so if you use it with a method that allows using route names (the url() helper for example) you can just use the route name. $this->url(array(), 'content');
This is how you would use a named route, personally I would probably consider renaming my module wms (if possible and practical) and just redirecting there from the default Index controller. Because once you start with named and custom routes it's hard to quit...

From your question that you
want to force them to get trough the WMS controller first
You can do one thing. Whatever you want to do in WMSController whenever a user types localhost/content/** you can put it in the parent class for ALL THE CONTROLLERS IN MODULE: 'CONTENT'. This way you can check for something/ perform operations everytime a request comes to this controller (no matter if the user wanted to go to the other module.)
class Content_AnyController extends MyControllers_Controller_Action_Admin{
....
}
where
class Reviewmo_Controller_Action extends Zend_Controller_Action{
public function init(){
//Things you want to do each time
}
}
This is what I think you want to achieve because if you want to just simply redirect to WMSController's ContentAction you can simply redirect to that controller.

Related

Extbase Hooks - execute code upon record creation

I want to create a standard typo3 extension but when I create a record (or modify it) I want to calculate something (in my case I want to call the Google Map API to get coordinates from a given address).
SO I search for a hook or something. Any idea?
One of my project example, may helps you for hook in backend when record has been changed.
In your extension file ext_localconf.php
// Hook for cancellation
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:femanager/class.tx_femanager_tcemainprocdm.php:tx_femanager_tcemainprocdm';
hook file class.tx_femanager_tcemainprocdm.php where you can execute
your script
class tx_femanager_tcemainprocdm{
function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$reference){
// $status also called action like delete
// $table - table name of excute backend action
// $id - record UID
// $fieldArray - fields of your table
if($table = 'your_extension_table_name'){
// your script
}
}
}
Maybe this answer is useful to you.
Register your class as a data handling hook in your extension. This one "is called AFTER all commands of the commandmap" were executed. Maybe you need to look for a more appropriate one.
Then in your registered Hook i.e. 'typo3conf/ext/your_ext/Classes/Hooks/AfterCreate.php' do your calculation. Hope this sets you on the right track.
In my special case there was no need to calculate the coordinates when the record got saved. So I just used the listAction in the controller, check if coordinates are there and if not call the Google API (and send an email if the Google API does not give a coordinate back).
In another case where the new record comes from a frontend plugin and I had to do something with this data I used the createAction in the Controller. (I am not sure if the createAction is also called when the record is created from the backend.)

Importing dynamic path in Less mixin

I'm rewriting my Less css structure to be more scalable. I'm looking for an architecture that loads a templates for each media query for each template.
Preferably, I want to load this in a mixin. The current mixin looks like this (but does not allow specific component loading)
`
/**
* Progressive enhancing overrides (mobile first)
*
* Mobile loads "mobile.less"
* Wide mobile loads "mobile.less" and "widemobile.less"
* Tablet loads "mobile.less", "widemobile.less" and "tablet.less"
* etc.
*/
.progressive-enhancement() {
// Mobile layout
#media only screen {
#import (less) "../template/mobile";
}
(...)
}
So what I'm looking for is something like this (not working):
.progressive-enhancement(#component: main) {
// Mobile layout
#media only screen {
#import (less) "../template/#{component}/mobile";
}
(...)
}
This however, does not work, resulting in an error claiming that #component is undefined.
I think the problem is that Less tries to do the import before the mixing is called, not having the #component defined at that stage.
Is there any way to use #import dynamically with variables provided by the mixin?
Thanks in advance.
Yes, it's impossible. And, yes, this is because Less have to evaluate language entities in certain "typed" order instead of "top-to-bottom" order (roughly it's imports -> mixins -> variables etc.) because of lazy-evaluation principles (there're some internal workarounds possible to handle certain specific things with an exception to this, but those exceptions will never be anything but kludge).
As for your specific use-case, the easiest workaround at first glance would be to use imports instead of mixins, and let the components to specify their own names:
// progressive-enhancement.less:
#media only screen {
#import "#{component}/mobile";
}
// etc.
Then for each component you provide its "root" file:
// ../template/button.less:
& {
#component: button;
#import (multiple) "progressive-enhancement.less";
}
.
// ../template/toolbar.less:
& {
#component: toolbar;
#import (multiple) "progressive-enhancement.less";
}
etc.
And finally in your master file you just import those ordinarily:
// main.less:
#import "../template/button";
#import "../template/toolbar";
(Obviously file names and and their actual locations to be adjusted to your taste).
I'm answering my own question so i can use some formatting to show my workaround.
I have this directory structure:
less/
- components/
- navbar/
- mobile.less
- tablet.less
(...)
- config/
- defaults.less
- lib/
- grid.less
- mediaqueries.less
(...)
- template/
- base.less
- mobile.less
- widemobile.less
- tablet.less
(...)
- main.less
The main.less file import the required libraries (e.g. mediaqueries.less). These provide mixing to use (e.g. .progressive-enhancement()). The mediaqueries library has multiple mixins that take care of template loading. See the docblock:
/**
* Progressive enhancing overrides (mobile first)
*
* Mobile loads "mobile.less"
* Wide mobile loads "mobile.less" and "widemobile.less"
* Tablet loads "mobile.less", "widemobile.less" and "tablet.less"
* etc.
*/
In addition, main.less also includes template/base.less for common styling ,font loading, custom mixins etc.
Since it was not possible for the mediaqueries library to handle the components in a nice way. This logic was moved to the them files. E.g. mobile.less:
(...)
/**
* Imports
*/
#import (less) "../components/navbar/mobile.less";
#import (less) "../components/postslist/mobile.less";
#import (less) "../components/footer/mobile.less";
(...)
Whenever i need to overwrite a rule for a certain media query additional imports can be made to to other files (unfortunately no auto loading). E.g. tablet.less
(...)
/**
* Imports
*/
#import (less) "../components/navbar/tablet.less";
#import (less) "../components/postslist/tablet.less";
Note that the footer is unchanged from mobile.
This solution might be a bit more verbose than the solution provided by #seven-phases-max but I think it's cleaner since variables don't need to be abused as parameters.

Using Zend view helper from admin module with default module layout

I have a view helper being called in my layout that works fine in the default module, but I get an exception when I am in another module.
I have already changed my app.ini to use the default layout across all modules by setting:
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
And searching here and google provided me with another app.ini setting to add the view helper path for all modules:
resources.view.helperPath.Zend_View_Helper = APPLICATION_PATH "/views/helpers"
However instead of fixing the problem, that additional setting causes the Zend Exception to become a WSOD.
Without that second app.ini setting, I see the layout and get this exception:
Plugin by name 'AutoScript' was not found in the registry; used paths: Admin_View_Helper_: /Applications/XAMPP/xamppfiles/htdocs/dad/application/modules/admin/views/helpers/ Zend_View_Helper_: Zend/View/Helper/:./views/helpers/
With the helperPath.Zend_View_Helper ini setting I get a WSOD with the following:
Fatal error: Uncaught exception 'Zend_Loader_PluginLoader_Exception' with message 'Plugin by name 'AutoScript' was not found in the registry; used paths: Zend_View_Helper_: Zend/View/Helper/:./views/helpers/'
It appears the plugin loader is looking in public/views/helpers/ for the AutoScript.php file even though it should be using the APPLICATION_PATH value as a prefix.
My layout invocation looks like this
<?php $this->AutoScript(); ?>
My AutoScript.php file's class is defined in application/views/helpers/
class Zend_View_Helper_AutoScript extends Zend_View_Helper_Abstract {
public function AutoScript() {...}
}
My current fix is to copy the AutoScript.php file from application/views/helpers into modules/admin/views/helpers which fixes the issue, but duplicates a file. What am I missing? Do I have to add this view helper path programmatically by creating an _initView function in my bootstrap?
Typically, you would name your custom view helper with your own prefix, not the Zend_ prefix. Beyond that, there are several choices for where to put and name your view helpers.
If this view-helper is really a single-application helper, then I find it natural for it to reside somewhere in the application folder. Within that possibility space, I would ask if the view-helper will be used in a single module or across multiple modules.
If the view-helper is intended for use in a single module, then I depend upon the build-in resource-autoloader mappings and place my view-helper class Mymodule_View_Helper_Myhelper in the file application/modules/mymodule/views/helpers/Myhelper.php.
If the view-helper is intended for use across multiple modules , I might pull it up a little higher than the modules folder, say Application_View_Helper_Myhelper (assuming an appnamespace of Application) stored in
application/views/helpers/Myhelper.php. In this case, we need to tell the view that there are helpers with prefix Application_View_Helper_ in that directory. This can be done at bootstrap:
protected function _initViewHelperPaths()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->addHelperPath(APPLICATION_PATH . '/views/helpers', 'Application_View_Helper_');
}
Sometimes, you need a view-helper in one module that exists in another module and you cannot - in practical terms - move the original one around. In that case, one workaround is to define an empty shell of a view-helper in your consuming module extending your unmovable view-helper. In file application/mymodule/views/helpers/MyHelper.php:
class Mymodule_View_Helper_Myhelper extends Othermodule_View_Helper_Myhelper
{
}
This way, the code for the helper implementation is not duplicated. The module-specific resource-autoloader mappings will allow all those classes to be found when they invoked as view-helpers from a view-script.
Finally, if this view helper is to be used in multiple projects, then there is an argument for placing it outside of application scope, out in in the library folder. So perhaps a class MyLibrary_View_Helper_Myhelper stored in the file library/MyLibrary/View/Helper/Myhelper.php. As before, you would need to inform the view - probably at bootstrap or in a front-controller plugin - of the prefix/path mapping:
$view->addHelperPath(APPLICATON_PATH . '/../library/MyLibrary/View/Helper', 'MyLibrary_View_Helper_');
Note that in all cases above, the invocation of the view-helper functionality itself - say, inside a view-script - is:
<?php echo $this->myhelper($params) ?>
Note, in particular, the casing difference between the classname and the invocation.

Zend: Which Class/Controller should i access from out of the module?

I have a running application and added my first module. Everthing works fine. Now i want want to use my module in the existing application.
I have the following folders:
application
- classes
- configs
- controllers
- ....
- modules
- discount
- configs
- controllers
- layouts
- models
- plugins
- views
- ....
- views
In an existing class under application/class i want to use some functions that belong to the module.
Now my questions:
1) Where should i store these functions i want to access from outside?
2) How can i access these from outside?
I assume your module is already registered with your application, for example in application/configs/application.ini, like so:
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
After that, the files belonging to your module can be accessed anywhere you like, as they are now part of your application. So for example, in application/controllers/IndexController.php you could simply do:
$myModel = new Discount_Model_MyModel();

Incorrect page loading in MVC

We are currently hosting a asp.net mvc 2 website in IIS 6. In this application we override the 'Create Controler' method and configure a custom view engine. This engine specifies the location of the views depending on the url format. for example; if a user lands on www.asite.com/test/1.0/index.aspx
the view engine tells mvc to look for index.aspx in the 'sitedirectory/test/1.0/views/pages/' directory;
string versionDirectory = String.Format("~/{0}/{1}", offerCode, version.ToString("#0.0000"));
ViewLocationFormats = new[]
{
versionDirectory + "/Views/Pages/{0}.aspx",
versionDirectory + "/Views/Pages/{0}.ascx",
"~/Views/Pages/{0}.aspx",
"~/Views/Pages/{0}.ascx",
"~/Shared/Views/{0}.aspx",
"~/Shared/Views/{0}.ascx"
};
MasterLocationFormats = new[]
{
versionDirectory + "/Views/Layouts/{0}.master",
"~/Views/Layouts/{0}.master"
};
PartialViewLocationFormats = ViewLocationFormats;
The Issue that we are having is that when two or more users land on the site at roughly the same time,
the views that get loaded can get switched around. However the data that is shown for those views is correct.
does anyone have any ideas why this would be happening?
This is a (little) known issue - there is a problem with caching going on.
Take a look at this post:
http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx
And go through the comments.
I ended up implementing owe view engine that derives from IViewEngine directly and uses WebFormsViewEngine internally.