I have this library in CI that retrieves my latest twitter updates. It has a function that sends my latest updates as objects to my controller.
I would like to show these twitter updates on the footer of my page, so they're visible at all times.
Now my question is how I call these directly from a view? I know this is not a good practice in MVC but I don't see how else I could do this.
My controller currently takes care of all my different pages (it's a small website) and I don't think it's very good practice to call my twitter class at the end of every page-function in the controller and then send it through to the views.
Typycally I do this in my controller:
<?php
function index(){
$data['page'] = 'home';
//i don't want to call my twitter class here every single time I write a new page. (DRY?!)
$this->load->view('template', $data);
}
?>
And it loads the "template" view that looks like this:
<?php
$this->load->view('header');
$this->load->view('pages/'.$page);
$this->load->view('footer');
?>
So any suggestions how I should do this?
I have a helper library that takes a page Partial and wraps it in the master theme. You can use the optional parameter on your load->view to render to a string.
Then when you render your master page, you can load the twitter updates, and display them. Although, I highly suggest caching your twitter response for 5 minutes at least, will save you a LOT of overhead.
Example:
// Controller somwhere:
$content = $this->load->view('pages/'.$page, array(), true);
$this->myLibrary->masterPage($content);
// Your library:
function masterPage($content)
{
$twitterData = $this->twitter->loadStuff(); // whatever your function is
$twitter = $this->load->view('twitter_bar', array('data' => $twitterData), true);
$this->load->view('master', array('content' => $content, 'twitter' => $twitter);
}
An alternative approach is to use a base controller. All my controllers extend my custom base controller which holds things I need on every page, for example an object containing the current user.
Related
I am creating a Joomla 2.5 component. In the backend I created a model/view/controller 'Members' which shows a grid. I also created an MVC 'Member' which is used to add or edit a member from the grid. So far so good.
Now, I would like to add a frontend view that is very similar to the 'Member' view in the backend, but this one is meant for visitors so they can subscribe themselves. It has to look more user friendly than the backend form, so I will create a slightly different 'Member' view in the frontend, but I would really like to reuse the form file (/administrator/components/mycomponent/models/forms/member.xml) from the backend!
So, my question is how my frontend view can find and use that backend form?
You definitely have to load it in the model. Your model has to extend JModelAdmin and then the getForm function has to load the form
public function getForm($data = array(), $loadData = true) {
// Get the form.
JForm::addFormPath(JPATH_COMPONENT_ADMINISTRATOR . '/models/forms');
JForm::addFieldPath(JPATH_COMPONENT_ADMINISTRATOR . '/models/fields');
$form = $this->loadForm('com_dpattachments.attachment', 'attachment', array('control' => 'jform', 'load_data' => $loadData));
if (empty($form)) {
return false;
}
....
}
I'm using the same approach in my DPAttachments component, it is for Joomla 3.1 but the main code, to use the same model and form on the front and back, should also run on Joomla 2.5. Here is the link to the getForm function
https://github.com/Digital-Peak/DPAttachments/blob/master/com_dpattachments/admin/models/attachment.php#L102
If you are following Joomla MVC guidance your frontend should be able to pick-up the forms automatically.
In your view (though it should request it from the model actually) you can write:
$formsPath = JPATH_ADMINISTRATOR.DS.'components'.DS.'com_mycom'.DS.'models'.DS.'forms';
$this->form = JForm::getInstance('myform', $formsPath.DS.'myform.xml');
You can also look at the summer of code cm_config project which pulls the config forms and the templateDetails form to the front end using JSON. https://github.com/Buddhima/joomla-cms/tree/gsoc_com_config or the com_services branch.
I don't really know how to word the title well, but here's my issue. I decided instead of having 25 controllers to handle pages, I have one PageController with a viewAction that takes in a :page parameter - for example, http://localhost/website/page/about-us would direct to PageController::viewAction() with a parameter of page = about-us. All of the pages are stored in a templates folder, so the viewrenderer is set to render application\templates\default\about-us.phtml.
I did this so I can consolidate and it seemed like a better approach. My question is the following: lets say when the page request is contact-us, I would need a Zend_Form to be used within the contact page. So, I would need a way within PageController::viewAction() to recognize that the page needs to have a form built, build the form, and also upon submission the need to process it (maybe this should be handled in an abstract process method - not sure).
I have no idea how to implement this. I thought maybe I can store a column with the name of a form and a connecting page identifier. Even better, create a one-to-many page to forms, and then in the submission loop through the forms and check if submitted and if so then process it (maybe there is a isSubmitted() method within zend_form. I really don't know how to handle this, and am looking for any help i can get.
Thanks!
Here is something that came to mind that may work or help point you in a direction that works for you.
This may only work well assuming you were to have no more than one form per page, if you need more than one form on a page, you would have to do something beyond this automatic form handling.
Create a standard location for forms that are attached to pages (e.g. application/forms/page). This is where the automatic forms associated with pages will be kept.
In your viewAction, you could take advantage of the autoloader to see if a form for that page exists. For example:
$page = $this->getParam('page');
$page = ucfirst(preg_replace('/-(\w)/ie', "strtoupper('$1')", $page)); // contact-us -> ContactUs
$class = 'Application_Form_Page_' . $page;
// class_exists will invoke the autoloader to map a class to a file
if (class_exists($class)) {
// a form is defined for this page
$form = new $class();
// check if form was posted
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()) {
// form is valid - determine how to process it
}
}
// assign the form to the view
$this->view->pageForm = $form;
}
All this really leaves out is the action you take to process a specific form. Since the contact form will likely generate an email, and another form may insert data into a database, you will need some sort of callback system or perhaps another class that can be mapped automatically which contains the form processor code.
Anyway something along those lines is what came to mind first, I hope that helps give you some more ideas.
I am currently working on a project developed using Zend Framework, based on the structure of my web page design I have reached a point where I have to pass a small number of variables to my layout from each Controller/Action. These variables are:
<?php Zend_Layout::getMvcInstance()->assign('pageId', 'page1'); ?>
<?php Zend_Layout::getMvcInstance()->assign('headerType', '<header id="index">'); ?>
The reason for passing this information is firstly, I pass the page id as the multi column layout may change depending on the content being displayed, thus the page id within the body tag links the appropriate CSS to how the page should be displayed. Secondly I display a promotional jQuery slider only on the index page, but I need the flexibility to have it displayed on potentially multiple pages in case the wind changes and the client changes their mind.
My actual question: Is there a more appropriate method of passing this information to the Layout that I am overlooking?
I am not really questioning whether the information has to be sent, rather is there some Zend Framework feature that I have, in my haste, overlooked which would reduce the amount of repetitive redundant code which may very well be repeated in multiple Actions within the same controller?
You could turn that logic into an action helper than you can call from your controllers in a more direct way. You could also make a view helper to accomplish the same thing but view helpers usually generate data for the view rather than set properties.
// library/PageId.php
class Lib_PageId extends Zend_Controller_Action_Helper_Abstract
{
public function direct($title, $pageId, $headerType)
{
$view = $this->getActionController()->view;
$view->headTitle()->append($title);
$view->pageId = $pageId;
$view->headerType = $headerType;
}
}
In your controller actions you can now do this:
$this->_helper->PageId('Homepage', 'page1', 'index');
// now pageId and headerType are available in the view and
// Homepage has been appended to the title
You will also need to register the helper path in your Bootstrap like this:
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPrefix('Lib');
}
Doing it like that can reduce the amount of repetitive code and remove needing to assign the values from the view. You can do it in the controller very quickly. You can also have default values in the case that the helper hasn't been called.
You shoudn't really be passing anything from the view to the layout, for a start the view should be included IN the layout, not the other way around.
So, setting your page title should be done using similar code to what you have, but inside the controller action being called:
$this->view->headTitle()->append('Homepage');
And the other two issues - you need to rethink as I stated to begin with. Maybe you're misunderstanding the layout/view principle? If you include the different views per action, then you simply change the div id when needed, and include the header for your banner only in the index.phtml file.
I need to give the front-end designer the ability to choose whether or not to display a single xml feed or an mash-up, from the view.phtml file
This means I need to be able to call a method from the controller or model which then returns a variable to the view containing the requested feed(s).
So how do I access methods of the controller or model from the view?
you don't call controller methods in view , but you can create an instance of model (for read only purposes) inside view and then call its public methods .eg
Foo.phtml
<?php $feedsTb = new Default_Model_Feeds() ?>
<?php $allFeeds = $feedsTb->fetchAll(); ?>
I don't know if i got your problem right, but this is something i'd probably do in a way like
Controller:
if($this->_getParam('single')) {
$this->view->data = $model->getFeedSingleData();
$this->render('single_feed.phtml');
} else { //mashup
$this->view->data = $model->getMashUpData();
$this-render('mashup_feed.phtml');
}
Though admittedly an example like this is better off with two different actions (singleAction() and mashupAction())
But i really don't know if i got your problem figured out at all :S You may explain it further
This might sound like an odd scenario, but I've got two forms on one page. One is just posting back to itself. I made the second post to another action to keep the code cleaner. Maybe not the right choice...
The problem I'm having now is that if that second form doesn't validate, I redirect back to the page with the form but I don't know how to keep my form fields filled in with the original information the user entered. Is there a way to do that and keep posting to two separate actions, or do I need to just bite the bullet and have both forms post back to the same action and deal with the messy logic?
I would submit both forms to the same action. There really shouldn't be anything too messy about it. In each form include a hidden field to signify which form is being submitted.
Application_Form_Login:
/* other form elements */
$this->addElement('hidden', 'login', array(
'value' => 1
));
Application_Form_Register:
/* other form elements */
$this->addElement('hidden', 'register', array(
'value' => 1
));
Controller:
$loginForm = new Application_Form_Login();
$registerForm = new Application_Form_Register();
if($this->_request->isPost()) {
if($this->_request->getPost('login')) {
if($loginForm->isValid($this->_request->getPost())) {
// validated, redirect
$this->_helper->redirector('profile', 'user');
}
}
if($this->_request->getPost('register')) {
if($registerForm->isValid($this->_request->getPost())) {
// validated, proceed as needed
}
}
}
$this->view->loginForm = $loginForm;
$this->view->registerForm = $registerForm;
View:
echo $this->loginForm;
echo $this->registerForm;
With this type of a setup, if either of your forms fail validation, isValid() will preserve any data that has been entered and you still redirect on a successful validation of one or both of the forms.
Personally, I think that each form should post to its own controller, as you have. This keeps the code for processing that form in a single place. The issue here is that you want to return to the original page on failed validation. But why? Why not simply redisplay the form in the target controller, just like you would if there were a single form on the page?
For example, consider a login form that appears on every page of a sie (perhaps because it in the site template/layout). It posts to something like AuthController::loginAction(). If the login fails, then you don't typically send him back to the page from which he came. You leave him at the login page, with the form as pre-filled from the $_POST as you want it to be (probably a username, but not his password).
See this answer for a similar discussion.
Update: Had another thought in this. If you really want to handle the processing in two different controllers in order to keep him on the page from which he posted the form, at least extract that form processing out into an action helper. This way, you could at least keep that form-processing DRY.
Update: Rob Allen has just written a great blog post "A form in your layout" in which he describes a method that uses an action-helper with a preDispatch() method that instantiates and processes the form. Very nice.
How do you redirect? I don't see the problem if you just display the form page again. You can prefill you forms using Zend_Form::populate().
Well, I would just keep both forms submitting on the same page.
I don't see why your code should get any less readable. Learn how to use action helpers and your controllers will suddenly look extremely simple and readable:
public function indexAction()
{
$request = $this->getRequest();
// send forms to view, so we can print them
// but also so we can access them in action helpers
$this->view->form = $this->_getForm('Form1', '/');
$this->view->form2 = $this->_getForm('Form2', '/');
if ($request->isPost())
{
// process the first form
if (isset($_POST['form_submit_button']) && $this->view->form->isValid($_POST))
{
$this->_helper->form($this->view->form->getValues());
}
// process the second form
else if (isset($_POST['form2_submit_button']) && $this->view->form2->isValid($_POST))
{
$this->_helper->form2($this->view->form2->getValues());
}
}
Each form's processing would have its own action helper.