How to convert Zend Framework website to mobile website? - zend-framework

i have made a huge website(front & admin side) in Zend Framework now i want to do the same
project in ZF but for mobile devices.
i will certainly use HTML5 & jQuery mobile but before go ahead & start my development for my mobile website i want to ask experts what is the nice,easy,efficient and optimized way to do so ???

You'll probably want to checkout the ContextSwitch View Helper - which allows you to switch the view script based on a 'format' parameter. You could use that (or extend it) to switch your view to a more mobile friendly template.
Take a look at the JSON Context specifically, it disables the layout - the same technique could be used to switch the layout if a mobile request is detected.
Of course, if you can accomplish what you need with some CSS media queries, that's certainly the way to go.
You might also find Zend_Http_UserAgent useful to detect the available features of the mobile device. Again, similar to what's possible with media queries, but may be useful nonetheless.
But the bottom line is there's not need to 'convert' the site, there are plenty of tools to allow the same site to be accessible to both desktop and mobile users.

Click
me,Read me and i am sure you will like me

As the anwser from Fawad Ghafoor as disappeared from the internet (still available in the web archive https://web.archive.org/web/20110225213957/http://www.web-punk.com/2010/03/zend-framework-applications-for-iphone-blackberry-co/)
I don't know if that's ok, but i'll copy and format the content of the website here.
Zend Framework Applications for iPhone, BlackBerry & Co
Mobile devices have become pretty important during the last years. This tutorial will show you how to pimp up your website and make it ready for mobile devices like iPhone, BlackBerry, etc.
Before we start: as in all other posts of this blog, I expect that you are a software engineer and implemented your web application using the MVC (model / view / controller) pattern and probably also Zend_Layout.
1. What We Need
Basically, the only thing you have to do when making your web application ready for mobile devices is to a) detect if the user surfs to your site using a mobile or non-mobile device and b) change the V in MVC according to the result of a).
However, I find it quite useful to extent this approach a little bit. Beside replacing your views with views for a mobile device, we will do two other things: we will also replace the layout (Zend_Layout) used for your web application and we will use a different translation file (Zend_Translation). It is obvious why replacing the layout is useful, but why do we need to use a different translation file? Well, actually we don’t have to, but I found it quite handy if you have translation file for the big screen (where you might want to use looong textual descriptions) and a translation file for your mobile devices (with crisp descriptions, error messages, labels, etc.)
As we will see later on, Zend Framework’s Context Switch (http://framework.zend.com/manual/en/zend.controller.actionhelpers.html) is (nearly) all we need… The ContextSwitch is an Action Helper that “is intended for facilitating returning different response formats on request”. This action helper comes with two different ready-to-use contexts: JSON and XML. For our example we will create an additional context named “mobile”.
Control Flow Schema is lost... at some point it was here : http://www.web-punk.com/wp-content/uploads/2010/03/mobile_wf-300x94.png
Basically, our control flow has to work as depicted in figure “Control Flow” (click on the figure to enlarge it). If a user surfs to http://mobile.example.com/controller/action, we directly set the correct context “mobile”. If a user surfs to http://www.example.com/controller/action, we check if he is using a mobile device. If he is using a mobile device, we’ll ask the user if he wants to use the mobile or desktop version of our web app. As we don’t want to ask the user whether or not he wants to use the mobile version each time he request a page, we will store her / his decision in a session variable (and only ask her again, if she was inactive for several minutes).
As an example for this workflow, please have a look at http://www.qulpa.com
2. Creating our Mobile Plugin
To achieve our goals, we will implement a small plugin. Before implementing this plugin we need a function that checks whether or not the current user is using a mobile device. You could use a smart solution like WURFL to do this. However, for our example, we will use a simple function that returs true if the user is using a mobile device and false otherwise. You’ll find dozens of functions that will do the job if you google for it. I’ll use a function that I found at Brain Handles.
Now, lets create our plugin. In your \plugins folder, create a file called Mobile.php and copy and paste the following source code:
<?php
class Plugin_Mobile extends Zend_Controller_Plugin_Abstract
{
// instead of defining all these parameters here,
// you could also put them into your application.ini
// if user is inactive for X minutes and surfs to
// www.example.com, we'll ask him again if he wants
// to user mobile or desktop version
private $ask_again_after_x_minutes = 10;
// used to test your mobile layout. Set this
// to 1 to emulate a mobile device
private $test_mobile = 0;
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
// did we already ask the user?
if (isset($_SESSION['mobileasked'])) {
// is mobile session still valid?
if (time() < $_SESSION['mobileasked']) {
// update session
$_SESSION['mobileasked'] = time() + $this->ask_again_after_x_minutes * 60;
// continue with requested page
return $request;
}
}
// otherwise, check if user is using a mobile device
// or if we are in test mode.
if ($this->checkmobile() || ($this->test_mobile == 1)) {
// if requested page != MOBILE.example.com
if (!(Zend_Registry::isRegistered('directmobile') && Zend_Registry::get('directmobile') == '1')) {
// set mobile session
$_SESSION['mobileasked'] = time() + $this->ask_again_after_x_minutes * 60;
// ask user if he wants to use mobile or desktop version
$request->setControllerName('index')
->setActionName('askmobile')
->setParam('format', 'mobile')
->setParams($request->getParams())
->setDispatched(false);
}
}
return $request;
}
/**
* This function returns true if user is using a mobile device. False otherwise.
* (c) by http://www.brainhandles.com/techno-thoughts/detecting-mobile-browsers
*/
private function checkmobile(){
if(isset($_SERVER["HTTP_X_WAP_PROFILE"])) return true;
if(preg_match("/wap\.|\.wap/i",$_SERVER["HTTP_ACCEPT"])) return true;
if(isset($_SERVER["HTTP_USER_AGENT"])){
// Quick Array to kill out matches in the user agent
// that might cause false positives
$badmatches = array("OfficeLiveConnector","MSIE\ 8\.0","OptimizedIE8","MSN\ Optimized","Creative\ AutoUpdate","Swapper");
foreach($badmatches as $badstring){
if(preg_match("/".$badstring."/i",$_SERVER["HTTP_USER_AGENT"])) return false;
}
// Now we'll go for positive matches
$uamatches = array("midp", "j2me", "avantg", "docomo", "novarra", "palmos", "palmsource", "240x320", "opwv", "chtml", "pda", "windows\ ce", "mmp\/", "blackberry", "mib\/", "symbian", "wireless", "nokia", "hand", "mobi", "phone", "cdm", "up\.b", "audio", "SIE\-", "SEC\-", "samsung", "HTC", "mot\-", "mitsu", "sagem", "sony", "alcatel", "lg", "erics", "vx", "NEC", "philips", "mmm", "xx", "panasonic", "sharp", "wap", "sch", "rover", "pocket", "benq", "java", "pt", "pg", "vox", "amoi", "bird", "compal", "kg", "voda", "sany", "kdd", "dbt", "sendo", "sgh", "gradi", "jb", "\d\d\di", "moto","webos");
foreach($uamatches as $uastring){
if(preg_match("/".$uastring."/i",$_SERVER["HTTP_USER_AGENT"])) return true;
}
}
return false;
}
Make sure, that you register this plugin! To do so you need something like this in your bootstrap:
// init PluginLoader. Adopt folder to your application...
$loader = new Zend_Loader_PluginLoader(array(
'Plugin' => APPLICATION_PATH . '/application/controllers/plugins',
));
// define plugin names and classes
$pluginList = array(
'plugin1' => $loader->load('Plugin1'),
'plugin2' => $loader->load('Plugin2'),
// [...]
'mobile' => $loader->load('Mobile'),
);
// get your front controller
$frontController = Zend_Controller_Front::getInstance();
// Register your plugins
foreach ($pluginList as $pluginClass) {
$frontController->registerPlugin(new $pluginClass());
}
3. Context detection
That’s all you have to do in your mobile plugin. Next thing we have to do is to make sure that we detect the correct context. We’ll do this in our bootstrap. Open your bootstrap.php and put something like this inside:
// set correct context
$domains = explode('.', $_SERVER['HTTP_HOST']);
if ($domains[0] == 'mobile' || $frontController->getParam('format') == 'mobile') {
if ($domains[0] == 'mobile') {
// if set, user will be redirected directly to requested page
Zend_Registry::set('directmobile', '1');
}
Zend_Registry::set('context', '\mobile');
} else {
Zend_Registry::set('context', '');
}
4. Asking the User
As we would like to ask the user if he wants to use the mobile or desktop version of our application, we will create a simple action in our index controller. We will redirect the user to this controller / action in our mobile plugin (see chapter 2).
Open your IndexController.php and create an askmobileAction:
public function askmobileAction()
{
// nothing to do here...
}
This action basically does… well, nothing ;-). Now, let’s have a look at the askmobile view. In your views folder, which probably will be \views\scripts\index create a file called askmobile.mobile.view and put something like this inside:
How do you want to use this application?<br/>
MOBILE VERSION
<br></br>
DESKTOP VERSION
That’s not really complicated, isn’t it? As you can see, the name of this view differs from the name of all the other views. As we will see later in this tutorial, ContextSwitch will make sure that the view name.MOBILE.phtlm is being called instead of name.phtml, if we are in the context MOBILE.
5. Your Mobile Layout
The next step is to create a unique layout for our mobile version. Whether or not this is necessary depends on your application. However, in most cases it will make sense to a complex layout for the desktop version of your application and a lightweight layout for the mobile version.
First, create a directory in your \layouts folder called \mobile (the full path with probably be something like \application\layouts\mobile but this depends on your application). Create a file called layout.phtml in this folder and put something this inside:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headTitle() . "\n" ?>
<?php echo $this->headLink() . "\n" ?>
</head>
<body>
<div id="header">This is your header</div>
<div id="content"><?= $this->layout()->content ?></div>
<div id="footer">This is your footer</div>
</body>
</html>
That´s our very simple layout for the mobile context. It is very likely that your layout will be much more complex even if you create it for mobile devices as you will probably include a CSS file, etc.
6. Putting everything together
We are already nearly finished. The last step is to use the context in your controllers. For this tutorial we will use the init() method of the IndexController, which you can use as template for all the other controllers in your application. Actually, instead of copying this code to all your controllers I prefer a smarter way that makes use of OO-Design paradigms (e.g., create a class MyMobileController that extends Zend_Controller_Action and get all the necessary parameters from your application.ini), however, this will do the job for this tutorial.
Open your IndexController.php file and copy and paste the following source code into it:
/**
* Initializes the controller & context
*
* #return void
*/
public function init()
{
parent::init();
// are we in the mobile context?
if (Zend_Registry::get('context') == '\mobile' || $this->getRequest()->getParam('format') == 'mobile')
{
// Mobile format context
$mobileConfig =
array(
'mobile' => array(
'suffix' => 'mobile',
'headers' => array(
'Content-type' => 'text/html; charset=utf-8')),
);
// Init the action helper
$contextSwitch = $this->_helper->contextSwitch();
// Add new context
$contextSwitch->setContexts($mobileConfig);
// This is where you have to define
// which actions are available in the mobile context
// ADOPT THIS TO YOUR NEEDS!
$contextSwitch->addActionContext('index', 'mobile');
$contextSwitch->addActionContext('askmobile', 'mobile');
// enable layout but set different path to layout file
$contextSwitch->setAutoDisableLayout(false);
$this->getHelper('layout')->setLayoutPath(APPLICATION_PATH . '/application/layouts/mobile');
// Initializes action helper
$contextSwitch->initContext('mobile');
}
}
7. Create your Mobile Views
Finally, you have to create your mobile views. For each view that is available in the mobile context (as defined in the init() method of your controllers), you have to create a mobile view. So, if you have an action called myaction you will need a myaction.phtml for the desktop version and a myaction.mobile.phtml for the mobile version of your application.
Congratulations! You’ve just created your first mobile web application ;-)
Appendix: Translation Files for a Mobile Device
As promised in chapter 1 we will use a different translation file for our mobile device / mobile context. This is quite handy as you might want to have shorter labels, description texts, error messages and so on. Of course, if you don’t need something like this you may simply skip this appendix.
Basically, all you need to do is to check in which context the application is and load the corresponding translation file.
Let’s assume that you store your translation files in the \application\translations\ folder and that you have an english and a french version of your application. Beside your fr.php and en.php files you should have a mobile version for each language in your translations folder: mobile_en.php and mobile_fr.php. The followin code snippet will load the corresponding translation file:
// Init Zend_Locale with corresponding language (assuming that $lang is set to 'en' or 'fr')
// and store the Zend_Locale object in the registry
Zend_Registry::set('Zend_Locale', new Zend_Locale($lang));
// Load translation file and store it in the registry
$langFile = APPLICATION_PATH . '/application/translations/';
if (Zend_Registry::get('context') == '\mobile') {
// if context = mobile, get translation file for mobile device
$langFile.= 'mobile_' . Zend_Registry::get('Zend_Locale')->getLanguage() . '.php';
} else {
$langFile.= Zend_Registry::get('Zend_Locale')->getLanguage() . '.php';
}
Zend_Registry::set(
'Zend_Translate', new Zend_Translate('array', $langFile)
);

Related

Moodle 3.3 - check if a user is authenticated in Mustache template

I'm creating a mustache template for a Moodle site and want to display some content on the front page but only if the user is not yet logged in. I was hoping I could do something like this in the template:
{{^usernotloggedin}}
My content for users not logged in.
{{/usernotloggedin}}
However I can't find any documentation on the user variables available to mustache to test if a user is authenticated or not.
Any advice of where to look or how to implement this would be great.
You would need to adjust the code that calls the template to add that data to the context that is passed to the template. In that case you can use the isloggedin() function to set the value you want to pass to the template.
I hope I'm not quite late to this question by anyhow I'd like to add my answer to this as well
Your mustache files are simple templates which cannot perform logic. What you can do is
in your controller or the file which calls the render function (which renders the mustache file and gives HTML), apply a check there
require( '/path/to/moodle/config.php' );
if (isloggedin()) {
echo "you are logged in";
}
Once you have applied the check you can send the array with a flag identifier (ONLY TRUE or FALSE) which the mustache files can understand.
for eg
in your controller/block etc you can do the following
$tagcloud = core_tag_collection::get_tag_cloud($this->config->tagcoll, $this->config->showstandard == core_tag_tag::STANDARD_ONLY, $this->config->numberoftags, 'name', '', $this->page->context->id, $this->config->ctx, $this->config->rec);
$content = $tagcloud->export_for_template($OUTPUT);
require( '/path/to/moodle/config.php' );
$flag = isloggedin() ? TRUE : FALSE;
array_push($content, $flag);
$this->content->text = $OUTPUT->render_from_template('core_tag/search_course_by_tags', $content);
and in your mustache file
{{#flag}}
your fancy code here which will onyl work if the user is logged in
{{/flag}}

Fiori -- Cross application navigation; Handling startup parameters?

This question is related to:
Fiori - Cross Application Navigation
http://help.sap.com/saphelp_uiaddon10/helpdata/en/07/9561b716bb4f2f8ae4e47bacbdb86d/content.htm
Remove URL params on routing
My use case is like this:
I have multiple applications that should link to others (deep).
Since documentation of cross navigation mention to avoid deep links I decided to use a startup parameter.
For example:
Application A has a list of some items in the detail view of one item there is a reference to another application B that contains some other details.
Assume A shows article details and B shows some details of a producer of an article.
Application A would now use some navigation like this:
sap.ushell.Container.getService("CrossApplicationNavigation").hrefForExternal({
target : { semanticObject : "ApplicationB", action : "display" },
params : { "someID" : "102343333"}
})
Now in application B I use code like this inside the Component.js at the end of the init method.
var oRouter = that.getRouter().initialize();
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
}
First question: Is this the right place for handling the startup parameters?
Second question: If I using the navigation the startup parameter will still be in the code, I would prefer to remove it, but how?
Update
In the target application (B) it would lead to the following URL:
https://server/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html?sap-client=100&sap-language=EN#SemObject-display?someID=102343333&/SomeView(102343333)/
Anyhow I would prefere to have something like this:
https://server/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html?sap-client=100&sap-language=EN#SemObject-display?/SomeView(102343333)/
The parameter must be retrieved as
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
as you write. In Fiori applications, the startup parameters injected into the Component data of your constructor may have been renamed, enriched by further default values etc.. Thus they may be distinct from the parameter one observes in the url. Applications are advised to refrain from trying to inspect the URL directly.
If one supplies a very long set of url parameters, one will observer that the FLP replaces some of them with sap-intent-param=AS123424 ("compacted URL") to work around url length restrictions on some platforms and in bookmarks, in the
getComponentData().startupParameters one will receive the full set of parameters).
As to the second question.
No, there is currently no way to "cleanse" the URL and avoid the redundancy between and inner app route.
SemObject-display?someID=102343333&/SomeView(102343333)/
which after navigation may look like
SemObject-display?someID=102343333&/SomeView(102343999)/
App was started with 102343333, but then user navigated within the app to another item (102343999).
Any change in the "Shell-part" of the has (SemObject-display?someID102343333) will lead to a cross-app-navigation (reinstantiation of your component) with a different startupParameter.
(There are cases where this is desired in the flow, e.g. a cross navigation from a OrgUnit factsheet to the parent OrgUnit factsheet via a link).
There were ideas within SAP to fuse the inner-app routes and the intent parameters, but they were not carried out, as it's mostly url aesthetics.
Note: To support boomarking, one has to respect both startup parameters and
inner app route during component instantiation,
assuming the user created a bookmark on
SemObject-display?someID=102343333&/SomeView(102343999)/
(While he was looking at 9999(!)).
When reinstantiating the app, the inner app route should take higher precedence than startup-parameters.
So amend the code to:
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
if (sap.ui.core.getHashChanger().getHash()=== "") {
// if no inner app route present, navigate
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
}
}
https://sapui5.netweaver.ondemand.com/#docs/api/symbols/sap.ushell.services.CrossApplicationNavigation.html
SAP Fiori Launchpad for Developers, Navigation Concept
http://www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/907ae317-cb47-3210-9bba-e1b5e70e5c79?QuickLink=index&overridelayout=true&59575491523067
I was having issues navigating from a Fiori elements app in to a deep page in a freestyle UI5 app and then answer from #user6649841 provided most the solution for my requirement.
In my instance, navigating from the elements list report (app "A") in to the target freestyle app (app "B") I didn't want the worklist/initial page in app B to display at all and instead go straight to the detail page without a flickering of the initial app screen.
The below worked for me, note though it doesn't solve the ugly URL issues. In my case I'm not fussed about it as my nav back will nav back to the elements list report (App A) and never show the worklist page in App B so the user will never make another search on top of this URL which would lead with inconsistent inner and outer keys
Component.js (at end of init function after all the standard sap code, but before router initialization):
var oComponentData = this.getComponentData();
var startupParams = oComponentData.startupParameters;
if (startupParams && startupParams.myQueryStringParamName && startupParams.myQueryStringParamName[0]) {
//In my case using hash changer as I dont want the original landing page (default route) to be
//in the history, so the detail page loads straight away and nav back will cause to nav back to App A
var hashChanger = sap.ui.core.routing.HashChanger.getInstance();
hashChanger.replaceHash("detailPage/" + startupParams.myQueryStringParamName[0]);
}
//initialise after the above so the new hash is set and it doesnt initially load the
//page assigned to the default route causing a flickering and nav slide effect
this.getRouter().initialize();
Looking at the UI5 SDK in UI5 1.48 and above in the initialize method of router you can pass in a boolean to tell it to ignore the initial hash so possibly can do a simpler implementation in newer releases of UI5
Is Component.js right place for handling the startup parameters?
Depends,if you have multiple views and you want to dynamically route based on the incoming parameters. Else you can handle in specific view also.
Your second question was not quite clear to me.
Nevertheless, if you want to only specific cases of startup parameters, then from Source App, set some flag to understand where is the request coming from and handle accordingly. So this way, your normal navigation won't be tampered.

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.

Access images or doc outside public folder in zend framework

I developing an application in zend framework. I want to store certain secure images and pdf documents outside public folder like /project/data/uploads or /projects/application/data/uploads.
I am not able to access the images/pdf documents other than public folder.
Can someone suggest a way to do it.
thank you
You have to have a separate action that knows how to fetch and deliver all that stuff. Something like this:
public function viewpdfAction()
{
$id = (int) $this->_getParam('id', 0);
// You implement some function - either here in your controller
// or someplace else - to get the pdf name from the passed id.
// Alternatively, you can pass the name itself. Up to you, of course.
// The key is that the request somehow identifies the file requested.
$pdfName = $this->_mapPdfIdToName($id);
// The path to the real pdf
$pdfFile = '/project/data/uploads/pdf/' . $pdfName;
// Disable rendering
$this->_helper->viewRenderer->setNoRender(true);
// Send the right mime headers for the content type
$this->getResponse()
->setBody('')
->setHeader('Cache-control', 'public') // needed for IE, I have read
->setHeader('Content-type', 'application/pdf')
->setHeader('Content-Disposition', sprintf('attachment; filename="%s"', $pdfName));
// Send the content
readfile($pdfFile);
}
Of course, some of this can be pushed down into service classes to keep the controller as thin as possible. Everyone has different tastes in this regard.
I confess that this code not completely tested, mostly trying to give the basic idea. If I have made a total bonehead error in here, please let me know.
Hope it helps!

Running a premade bulletin board through my Front Controller in Zend

I tried to ask this once, but I think that my former question was too unclear for you guys to answer, so I'll try again
I'm making a website using the Zend Framework, and am trying to include the premade messageboard Phorum. So far, I've made it work by not running it through my bootstrap using my .htaccess file. What I'd like to do i'd like to do is to be able to run it through my bootstrap so that I can use my previously created Layouts and Classes that I can only run through Zend.
For example, I have a premade sign in system that works through Zend_Auth. I have the person's data saved in Zend_Session. I load the user's profile through a controller. I have a service layer for the model that connects to my database on behalf of the user. There are several other dependencies that, as far as I can tell, I need the bootstrap for.
Phorum is basically just a large set of PHP scripts that are dependent on GET parameters. My original idea had been to use a controller to render the scripts. An example of what that URI would look like is this: My-Site.com/messageboard/list.php?1,3 with messageboard being the messageboardController. While this works for loading list, it can't capture the GET parameters, which Phorum is dependent on. Due to the complex nature of Phorum, it would be nearly impossible for me to be able to go in and make it something like My-Site.com/messageboard/list/1/3 or anything along those lines. The URI has to be the former, as it is built in to Phorum.
I have tried using frames. I got to keep my log in panel up top, and had the body of the page be a frame, but it was unbookmarkable, and the back button made everything outrageously difficult. I also couldn't get the frame to talk to the parent page in Zend well, so frames aren't an option.
Does anyone have a way that I can do this? What I need, in essence, is to take the script (ex. list.php?1,3) and place whatever it would render, after having used the 1,3 parameters, into a div in the "body" div of my layout. As far as I can tell, render doesn't seem to be able to capture the GET parameters. Does anyone know of a way I can do this.
Any ideas would be immeasurably appreciated. Thank you for your help!
This isn't a trivial thing to process, however, it is possible to write a custom route, along with some controller magic to handle this sort of thing and include the proper php file:
First of all - Your route should probably be (in ZF1.9 application.ini conventions)
resources.router.routes.phorum.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.phorum.route = "messageboard(?:/(.*))?"
resources.router.routes.phorum.defaults.controller = "phorum"
resources.router.routes.phorum.defaults.action = "wrapper"
resources.router.routes.phorum.defaults.module = "default"
resources.router.routes.phorum.defaults.page = "index.php"
resources.router.routes.phorum.map.1 = "page"
Now all requests to messageboard/whatever.php should be routed to PhorumController::wrapperAction() and have 'whatever.php' in $this->getRequest()->getParam('page')
Then it should become a simple matter of redirecting your "wrapper" action to include the proper php file from phorum. I have added some code from a similar controller I have (although mine didn't include php files - it was meant solely for serving a directory of content)
public function wrapperAction() {
$phorumPath = APPLICATION_PATH."../ext/phorum/";
$file = realpath($phorumPath . $this->getRequest()->getParam('page');
if (!$file || !is_file($file)) throw new Exception("File not found");
// disable default viewRenderer - layout should still render at this point
$this->_helper->viewRenderer->setNoRender(true);
// determine extension to determine mime-type
preg_match("#\.([^.]+)$#", $filename, $matches);
switch (strtolower($matches[1]))
{
case "php":
// patch the request over to phorum
include($file);
return; // exit from the rest of the handler, which deals specifically
// with other types of files
case "js":
$this->getResponse()->setHeader('Content-Type', 'text/javascript');
ini_set('html_errors', 0);
break;
case "css":
$this->getResponse()->setHeader('Content-Type', 'text/css');
ini_set('html_errors', 0);
break;
case "html":
$this->getResponse()->setHeader('Content-Type', 'text/html');
break;
// you get the idea... add any others like gif/etc that may be needed
default:
$this->getResponse()->setHeader('Content-Type', 'text/plain');
ini_set('html_errors', 0);
break;
}
// Disable Layout
$this->_helper->layout->disableLayout();
// Sending 304 cache headers if the file hasn't changed can be a bandwidth saver
$mtime = filemtime($fn);
if ($modsince = $this->getRequest()->getServer('HTTP_IF_MODIFIED_SINCE'))
{
$modsince = new Zend_Date($modsince);
$modsince = $modsince->getTimestamp();
if ($mtime <= $modsince) {
$this->getResponse()->setHttpResponseCode(304);
return;
}
}
$this->getResponse()->setHeader('Last-Modified', gmdate("D, d M Y H:i:s",$mtime). " GMT");
readfile($fn);
}
Please - Make sure to test this code for people trying to craft requests with .., etc in the page.