My app is supposed to work like this. First, the default Action of the Default controller (according to URL) does it's job. For the purpose of this question lets name it MyController and indexAction.
Then it forwards ($this->_forward) to my LayoutController menuAction which renders navigation part (menu from database) and forwards to footerAction, which then renders footer from database (things which are in db but must be visible in every single page).
Finally /views/scripts/my/index.phtml is rendered in the layout with $this->layout()->content.
Question is, how shall I make other parts of layout rendered in their appropriate places? Do I need additional files menu.phtml and footer.phtml which somehow would be rendered by LayoutController menuAction and footerAction and somehow inserted in the appropriate places inside layout.phtml? Or can I have just one layout.phtml script with all the html inside, and menuAction / footerAction just provides the text from DB to be inserted?
I'm interested in good programming practice side as well as technical "how to" if you can.
I think you should consider to use just one layout.phtml as your template. So your default action will render not the contents of the layout but the content of the page itself. For example, in a blog application, you'll have the sidebar and the footer, also you will have the post content. Your ->viewPostAction() will render the post, and a plugin with ->postDispatch() method will render the layout contents in every page.
You can take as basis this question: how to call multiple controller action from within any action in ZF?
Related
In page.tpl.php of Drupal, the following code has variable $page which contains the html codes that are required to render part of the webpage.
<?php if ($page['content']): ?>
I'm trying to retrieve the updated content from DB at an interval and update a DIV without refreshing the whole page. My question is, where can I find the DB query codes from which $page came about?
page['content'] variable
When Drupal displays the "content" variable, think of it as big array of data that will be rendered in a specific section of the page.
Before that happens, it either retrieves data from the block settings of the native interface (block visibility settings) or from custom modules that override this original settings like f.e. context (https://www.drupal.org/project/context).
>> Template files
The template files are kinda like the last stop where data is built and ready to be rendered and delivered to the client.
In general, the best practice is keep the render templates intact and keep the logic and variables manipulation at the pre_hook levels .
>> So if you do wanna have "programmatic" control over what you can display you can f.e.:
Render specific nodes with "node_load" function and then using node_view($node)
f.e.
$node = node_load(23); //23 is random a node id
if (isset($node)) {
$node_data = node_view($node,'default''); // here's my node display data
print drupal_render($node_data); // here's my html
}
Render templates that aggregate different data with the "theme_render_template"
https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_render_template/7
Render views by using views_get_view('view name') like stated before.
Hooks like these might help you in adding/modifying the content you wish
template_preprocess : (hook templates
hook_node_view : (alter node array data before render)
page_alter : (alters page variables like content, header and so on)
hook_views_pre_render : (views is built, can alter render process)
hook_panels_alter : (for page manager and ctools approach)
>> Database queries
Doing a straight query to the database can also be done through the database api and then rendered, but be aware you might miss out the drupal hook power and end up having high maintenance code that escapes the convenient and safer Drupal way.
Hope it helps!
That content comes from inner node templates (if you are displaying node on that page) or i.e. view template....or...depending on what page you are displaying. But if we assume that you are displaying node page in some content type "player" you created content will "come" from template file "node--player.tpl.php"
https://www.drupal.org/node/1089656
Inside that file you can do database query (by using Drupal's database api) or even easier use Drupal's views module to query database:
https://www.drupal.org/project/views
What you are trying to do :
"I'm trying to retrieve the updated content from DB at an interval and update a > DIV without refreshing the whole page"
, is usually done with Javascript sending Http requests from the browser and not from PHP code executing server side in a Drupal template file, and is named AJAX. Doing AJAX with Drupal could be done in multiple ways, one of the recommended ones is with the use of the "Drupal AJAX Framework", resulting in PHP code with "Drupal AJAX API" calls server side that will generate for you the appropriate JavaScript client code renderer in the Drupal's output. The Drupal "Views" module may also help in this task, being "aware" of the Drupal AJAX framework. A good understanding of general AJAX mechanisms and of the Drupal AJAX framework are required to do this properly.
I have code that I want to run on every page load, such as looking up menu items, looking up the users details etc. These will be displayed on partial views that make up the main view.
Where do I place this code so that it can fill my partial views with each page load? I know I can just add the code to the top of the partial view itself, but this doesn't really follow the MVC pattern.
Is there a function that is always called that I can hook into in my base controller?
You can create a base viewmodel for the repeated code and make other viewmodels inherit from it.
...such as looking up menu items, looking up the users details etc
You're a bit unclear about the type of information you want to load: in case the info is a view-component then indeed you should create a base-view and inherit from it or include it (composition) in any other view.
But, in case it is "user-information" - the data should live in a model-component that again, may live as "base-model" object that is included in other model components.
I am working on a web application. This might be a silly question, but I want to know whether I am taking the good approach to this or not.
I want to have multiple views on one single view/page.
The Codeigniter documentation says that "A view is simply a web page, or a page fragment, like a header, footer, sidebar, ...".
I want to have a header, some quick search view, some other view and a footer for a example. Should I implement a controller to every view (header, quick search, footer, ...), or is it better to implement every view functions in a single controller? For instance, if I know that the header, footer, quick search views are going to always be there (even if their content might change) should I put functions for all those views in one controller?
Please, help.
one approach is to have a template view that has the elements you require.
see this pseudo-code example...
so, template_view.php has:
$this->load->view('header',$header);
$this->load->view('quicksearch',$quickssearch);
$this->load->view('body',$body);
$this->load->view('footer',$footer);
your single controller then calls the template with the parameters for each view.
$data = new stdClass();
$data->header = ....
$data->quickssearch = ....
$data->body = .....
$data->footer = .....
$this->load->view('template_view',$data);
I have a situation where I have several ways to perform the same activity in my php web app.
There is the "Manage Widgets" section of the app which has a form for creating new widgets and a list of existing widgets.
Then somewhere else in the app there is a button that pops up a dialog to add a new widget.
Then on the home page of the app there is another place where a form is embedded to add a widget (think home page portal).
My question is: What is the best practice for this? In this case all of the forms will be essentially the same. So my first instinct is to use the same code for all three of these scenarios. On the other hand, space on the home page could be smaller and layouts may have to differ between the three.
So even though it would be repetition, is it better to duplicate this form 3 times (there is a proper model layer, so the duplicated code would not include the logic to add/edit the widget)? Or try to force a single view in all of these scenarios? Both seem wrong to me and I am hoping for some ideas to discover some sort of middle ground.
One approach would be to have the markup (not the styles) for the form as a standalone file, which can then be included from anywhere you like.
You can then use AJAX to submit the form to a specific PHP script that handles the form submission and returns a meaningful JSON response. You can then display and style this JSON response on the page in question.
This way you have a single form (that can be styled differently) and a single handler for any view that's required to use the form.
i mean, the best way is compose form from other forms (Dont repeat yourself). You can use different templates for same form to change appearance of final form.
For example/idea you can check forms what is used in Nette Framework (http://doc.nette.org/en/forms)
T.
If you are just changing the styles, not the markup, I think the best approach is to add a specific class to the form element and then use Javascript (not Ajax, justa Javascript) to alternate between these clases as you need.
If your application do not use Ajax at all and you just generate web pages with PHP, is a simple matter of decide which class you form shoud have.
In CSS, you do something like this:
form.main { ... }
/* main form rules */
form.other { ... }
/* other form rules */
As I have understood, the main design idea of templating engines like Twig is to remove all PHP code from views, and to have the controller that renders a view have set all parameters that are necessary in that view.
However, imagine that a view consists of different "blocks": a header, a footer, a shopping cart and a productlist. You could have the order_controller.php check whether or not the customer is logged in (because if not, the header doesn’t contain the link "Log off"), as well as fetch a list of all available products (to show them in the product block), as well as fetch the contents of the shopping cart in the $_SESSION (to show them in the shoppingcart block).
However, it might be more interesting to have the order_controller only fetch one thing: the list of products. The view that will be rendered by the controller would then contain different includes for the other blocks (header, footer and shopping cart), but they wouldn’t include their views. They would include other controllers (showheader_controller, showfooter_controller and showcart_controller), which in turn would render their own single blocks (showheader_controller would only render the header-view etc…). In short: you would include controllers that render views in the main view. The logic that would check whether or not the customer is logged in would then be showheader_controller, for the simple reason that the header view is the only view that needs to know this. The logic that load the contents of the shopping cart from $_SESSION would be the showcart_controller, because the cart-view is the only view that needs to have access to this data, etc...
This way, you could have tons of controllers that all show the header, but the instead of having each controller repeat the logic to check whether or not the customer is logged in, you would only have it in one place (the controller that renders the header-view).
If there were a Twig function to include any external source on that spot in the view, the problem would be fixed (since I could just include the other controllers), but as it is it only allows for the including of other templates (that cannot have PHP-logic in them, otherwise it would kinda defeat the purpose).
The way I fix this now is to have the order_controller have this logic:
Fetch the productlist
Start the buffering of the outputstream (ob_start())
Include the controller that renders the header (showheader_controller)
Store the contents of the buffer in a variable $headerView.
Clean up the buffer
Start the buffering of the outputstream (ob_start())
Include the controller that renders the shopping cart (showcart_controller)
Store the contents of the buffer in a variable $cartView.
Clean up the buffer
Rinse and repeat...
In the view, I print the contents of the set variables:
{{ headerView | raw }}
The raw-filter has to be added, because the headerView variable contains html-tags.
It works perfectly, but it’s not exactly “neat”.
My question: would there be a better way to achieve this strategy?
First, this can be simplified by implementing the MVC separation better. The controller's job is pretty much solely to react to events and poke the model into doing appropriate things in reaction to this event. It is not the controller's job to hold hands with the view, nor is the view entirely dependent upon the controller.
The model is your core application, modeling all the things your application is supposed to do. The view's job is to visualize what is going on in the application, to give the user something to interact with. The controller is just a little glue between the user and your application, something that lets the user control the application.
As such, the controller reacts to events like "user visited homepage", triggers necessary events in the model, which causes the view to update to represent the new state of the application. The view can do whatever it needs to do. The view is not just a Twig template. The view can talk back to the model to get more information. In the end it is not the controller that needs to send necessary data to the Twig template, it's the view that needs to set the necessary data for the template before it renders it. Less code in controllers, more code in the view.
If you want to make this more modular, you can define custom Twig tags or functions which may fetch the necessary data from wherever it needs fetching. For instance:
<div class="head">{{ user_login_status() }}</div>
user_login_status is a Twig extension function which can talk to the model to get the data necessary to display the status.
Hope you get the idea.