Use database data in MVC Master Page - php

Suppose i'd like to display title of latest articles.
for particular Views , we use controllers to handle that. but for common section of pages like header or footer ,
How to display data(latest articles) from database (within MVC rules) ?
Note: I use php
Please check my approach:
app class:
<?php
class app{
public static function appLoader($app){
include 'apps/'.$app.'/'.$app.'.class.php';
new $app;
}
}
test.class.php :
class test extends app{
function __CONSTRUCT(){
return 'Hello World';
}
}
footer.php:
<footer>
<?php echo app::appLoader("test") // returns 'Hello World' ?>
</footer>

Note: This is w.r.t .Net MVC
If you are following MVC pattern - then there's a concept of "Partial Views" - which is just like user controls, and it can be placed in the main page.
Partial view is also an html page which might just div, no html body head etc because it will be rendered inside main html page
You might need to verify the syntax for Partial Views with PHP. The concept remains same for MVC.
There are various ways to display partial views.
One popular way is the one where Partial view is called by its action method - which will ultimately display the result(the partial view).
The Action method will return a "_Footer" Partial view - where you can put your HTML Code of displaying the data from DB(the latest articles).
The partial view must bind from the list of articles. which is popularly known as Strong Type Binding in .Net - which is nothing but mapping the view(HTML page) to a specific class to display the data from that class.
For your reference the below example can be referred(in .Net):
Create a partial view for footer(_Footer) and call it using Action Method(RenderAction - .Net). This action method can fetch the data from database and display in the partial view(_Footer)
The call to the action method be like from the view(html page):
#{ Html.RenderAction("Index", "Footer", new { Area = "Common", id}); }
And the Controller and action method like:
public class FooterController : Controller
{
public ActionResult Index(int id)
{
var vm = new FooterViewModel
{
Id = id
};
return this.PartialView("_Footer", vm);
}
}

Related

Include a css file into the header of the view that's calling a controller method

Basically what I'm trying to do is to implement a little chunk of html generated by a controller in a separate view into one main view. The problem is that I need custom styles for that little chunk of html and I can't know where I'll have to include it (manually), so I'd like the css to get appended to the file calling the function somehow from the controller when the method is being called.
More detailed explanation:
I'm programatically listing small custom panels to display some properties of each instance of my model (in this case, a window). In the main view, where I'm listing, there are a lot of them, so I decided to make a separate view file to create the panel and then simply return it via a function in the controller.
So in the home.blade.php I do as follows:
#foreach($order -> windows as $window)
{!!$window->drawPanel()!!}
#endforeach
Then in my Window controller I've got a method to return the view where the window is being displayed (!differently depeding on it's properties!) like that:
public function drawPanel()
{
return view('dogrami.windowPanelThumbnail', ['window' => $this]);
}
And then in the windowPanelThumbnail file I'm displaying accordingly the html needed. The problem is: to build my panel, I use some custom css which I can't include in the builder view, because it's getting called like 100 times.
The question is - how to append the style to the file that called the method in the controller.
Basically I'd like to do as follows:
public function drawPanel()
{
//$cssFile = pathToMyCssFile;//that's the instance containing my custom css
//$callingFile = ...//somehow retrieve an instance to the file that called that method.. in this case - the path to 'home.blade.php'
//if($calling.File already has the $cssFile included in it's header)
//don't do anything
//else
//$callingFile -> somehow include the $cssFile instance in the header
return view('dogrami.windowPanelThumbnail', ['window' => $this]);
}
I have no idea if it's possible so that's what I'm asking. Or if you have better ideas of how to achieve that, I'd be really thankful!
If you want to include your css dynamically you can use stacks https://laravel.com/docs/5.4/blade#stacks this way :
$links = ["all", "the", "links", "to", "css", "files"];
return view('yourview', [/*allyourdata, */, 'stylesheets' => $links]);
And in your view you can do :
#push('stylesheets')
#foreach($stylesheets as $stylesheet)
<link rel="stylesheet" type="text/css" href="{{ $stylesheet }}">
#endforeach
#endpush
And add #stack('stylesheets') in the head of your html
PS : a stack is a lifo data structure (last in first out), meaning that if you do several #push, the last one you do will be the first one echo'ed

PHP class implementation

I need a little bit of help understanding PHP Classes.
I'm ok with the code but its more the implementation, what to contain in a class, that I'm struggling to get to grips with.
Using a blog as an example site, on the homepage (or posts page) I'm going to have a list of multiple posts.
Would I:
A: Create a class to get the details for a single post and call that within a loop on index page.
B: Create a class that gets and returns all the posts for the page and each indivdual posts details within the same class.
C: Create a class to get the list of post for the page and a seperate class to get the indiviudal post details.
My gut is telling me its C, so I can reuse the individual post class on other parts of the site (ie individual post page) and resue the class to get all the post in other ways (maybe for feature posts or similar).
Any tips welcome.
Thanks in advance!
Technically, one class should do. No need for Multiple Classes that does essentially the same thing (with a very slight alteration). Consider the Empty Class below:
<?php
class Post{
protected $post;
protected $lastPost;
const POST_TYPE_SINGLE = 1;
const POST_TYPE_LIST = 2;
public function getPostList(){
// IMPLEMENTATION CODE
// TO GET ALL THE POSTS EXISTING WITHIN YOUR SYSTEM...
// NO HTML RENDERING...
}
public function getPostByID($postID){
// IMPLEMENTATION CODE
// TO GET RAW DATA FOR THE POST WITH THE ID $postID
// NO HTML RENDERING...
}
public function getDetailedView($post){
// IMPLEMENTATION CODE
// TO GET ONE SINGLE POST AS A HTML RENDER USING THE $post...
}
public function getListView($posts){
// IMPLEMENTATION CODE
// TO GET ALLS POSTS AS A HTML RENDER USING THE $posts...
}
public function getPostsByDate($date) {
// IMPLEMENTATION CODE
// TO GET ALL THE POSTS POSTED ON THE SAME DATE: $date..
}
public function getPostByAuthor($author){
// IMPLEMENTATION CODE
// TO GET ALL THE POSTS POSTED BY THE SAME AUTHOR: $author...
}
public function render($post, $postType=1){
// IMPLEMENTATION CODE
// TO RENDER THE POST AS HTML STRING TO BE DISPLAYED AT THE FRONT-END...
// COULD BE USED TO RENDER BOTH DETAILED AND LIST VIEWS DEPENDING ON
// THE VALUE OF $postType...
if($postType == self::POST_TYPE_SINGLE){
// CODE FOR HTML SINGLE POST RENDER
}else{
// CODE FOR HTML LIST-VIEW RENDER
}
}
}

Changing layout of view in Joomla 2.5

I know there are several similar topics around but I read and tried most of them but still can't figure out how to do this.
I have a written a component in Joomla 2.5 and it works so far. I have different views and I can load the views using the controller.php.
One of the views shows a table out of my data base (data about teams).
Now I'd like to have another layout of the same view which would display the data base table as a form so can change the content.
That's the file structure:
views/
- teams/
- - tmpl/
- - - default.php
- - - modify.php
- - view.html.php
That's out of the view.html.php file:
...
// Overwriting JView display method
function display($tpl = null) {
...
$this->setLayout('modify');
echo $this->getLayout();
// Display the view
parent::display($tpl);
}
I tried different combinations of setLayout, $tpl = ..., default_modify.php, etc.
but I always either get the default layout or some error like 'can't find layout modify'
I load the site with .../index.php?option=com_test&task=updateTeams
And the controller.php looks like this:
function updateTeams(){
$model = $this->getModel('teams');
$view = $this->getView('teams','html');
$view->setModel($model);
$view->display();
}
I had a similar problem, I created some kind of user profile view and wanted them to be able to edit the fields without having to create a new model for it (would have similar functions, hate redundancy...). What worked for me is to simply call the layout like this:
index.php?option=com_mycomponent&view=myview&layout=edit ("edit" would be "modify" in your case)
To do this I didn't touch the view.html.php (well I did at first but I didn't have to.). And you don't need to use the controller either. If you want to load the modify view, just add a button to your regular view linking to the modify layout. No need to change anything else.
I happen to have written a blog article about it, check it out if you want: http://violetfortytwo.blogspot.de/2012/11/joomla-25-multiple-views-one-model.html
Hope this helps.
Ok this is the problem .. you don't want another layout, you want a new MVC triad that is based on forms rather than rendering. So if you look at any of the core content components you will see in the backend they have a mvc for say ... contacts and one for contact and contact is the editor. If in the front end you will notice that com_content and com_weblinks have mvc for artice/weblink and then separate ones for editing.
You need a really different model and layout and set of actions for editng than for just rendering.
Old topic, but it might still help.
It seems that when one wants to change the layout, the $tpl must not be included in the display() or must be null.
So the previous code would be:
function display($tpl = null) {
/* ... */
$this->setLayout('modify');
// Display the view without the $tpl (or be sure it is null)
parent::display();
}

Correct way to deal with application-wide data needed on every pageview

I am currently involved in the development of a larger webapplication written in PHP and based upon a MVC-framework sharing a wide range of similarities with the Zend Framework in terms of architecture.
When the user has logged in I have a place that is supposed to display the balance of the current users virtual points. This display needs to be on every page across every single controller.
Where do you put code for fetching sidewide modeldata, that isn't controller specific but needs to go in the sitewide layout on every pageview, independently of the current controller? How would the MVC or ZF-heads do this? And how about the rest of you?
I thought about loading the balance when the user logs in and storing it in the session, but as the balance is frequently altered this doesn't seem right - it needs to be checked and updated pretty much on every page load. I also thought about doing it by adding the fetching routine to every controller, but that didn't seem right either as it would result in code-duplication.
Well, you're right, having routines to every controller would be a code-duplication and wouldn't make your code reusable.
Unlike suggested in your question comments, I wouldn't go for a a base controller, since base controllers aren't a good practice (in most cases) and Zend Framework implements Action Helpers in order to to avoid them.
If your partial view is site-wide, why don't you just write your own custom View Helper and fetch the data in your model from your view helper? Then you could call this view helper directly from your layout. In my opinion, fetching data through a model from the view doesn't break the MVC design pattern at all, as long as you don't update/edit these data.
You can add your view helpers in /view/helpers/ or in your library (then you would have to register your view helper path too):
class Zend_View_Helper_Balance extends Zend_View_Helper_Abstract
{
public function balance()
{
$html = '';
if (Zend_Auth::getInstance()->hasIdentity()) {
// pull data from your model
$html .= ...;
}
return $html;
}
}
Note that you view helper could also call a partial view (render(), partial(), partialLoop()) if you need to format your code in a specific way.
This is a pretty simple example, but to me it's enough is your case. If you want to have more control on these data and be able to modify it (or not) depending on a particular view (or controller), then I recommend you to take a look on Placeholders. Zend has a really good example about them here on the online documentation.
More information about custom view helpers here.
When you perform such a task, consider using the Zend_Cache component too, so you won't have to query the database after each request but let's say, every minute (depending on your needs).
What you are looking for is Zend_Registry. This is the component you should use when you think you need some form of global variable. If you need this on EVERY page, then you are best adding it to your bootstrap, if you only need it in certain places add it in init method of relavent controllers.
application/Bootstrap.php
public _initUserBalance()
{
$userId = Zend_Auth::getInstance()->getIdentity()->userId;
$user = UserService::getUser($userId);
Zend_Registry::set('balance', $user->getBalance());
}
application/layouts/default.phtml
echo 'Balance = ' . Zend_Registry::get('balance');
That wee snippet should give you the right idea!
In this case, I usually go with a front controller plugin with a dispatchLoopShutdown() hook that performs the required data access and adds the data to the view/layout. The layout script then renders that data.
More details available on request.
[UPDATE]
Suppose you wanted to display inside your layout the last X news items from your db (or web service or an RSS feed), independent of which controller was requested.
Your front-controller plugin could look something like this in application/plugins/SidebarNews.php:
class My_Plugin_SidebarNews
{
public function dispatchLoopShutdown()
{
$front = Zend_Controller_Front::getInstance();
$view = $front->getParam('bootstrap')->getResource('view');
$view->sidebarNews = $this->getNewsItems();
}
protected function getNewsItems()
{
// Access your datasource (db, web service, RSS feed, etc)
// and return an iterable collection of news items
}
}
Make sure you register your plugin with the front controller, typically in application/configs/application.ini:
resource.frontController.plugins.sidebarNews = "My_Plugin_SidebarNews"
Then in your layout, just render as usual, perhaps in application/layouts/scripts/layout.phtml:
<?php if (isset($this->sidebarNews) && is_array($this->sidebarNews) && count($this->sidebarNews) > 0): ?>
<div id="sidebarNews">
<?php foreach ($this->sidebarNews as $newsItem): ?>
<div class="sidebarNewsItem">
<h3><?= $this->escape($newsItem['headline']) ?></h3>
<p><?= $this->escape($newsItem['blurb']) ?></p>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
See what I mean?

Two controllers for one view, CodeIgniter?

Hey guys, I am new to CodeIgniter and need some help. I have a controller that formats the content area of a post. The problem is that I also need to create a sidebar that contains dynamic groups, and a right column that contains recent posts. This isn't hard, the problem I'm running into is that I want the sidebar, and right column on every page, and I don't want to recode the same bits to get the data in every controller.
What would be the best way to do this without copy/paste?
There are a lot of ways to do this.
1) Templating: This is my preference for most cases (because my templates are complex), I render my view into a variable using something like:
$content = $this->load->view('myview', $page_data, true);
Then I load it into the template parser (fyi you could load it into another view too) like this:
$this->load->library('parser');
$data = array(
'page_title' => 'My Page Title',
'page_content' => $content,
'side_bar' => side_bar(), // function which generates your side bar
'right_col' => right_col() // function which generates your right column
);
$this->parser->parse('my_template', $data);
Then your template is like:
<html>
<head>
<title>{page_title}</title>
</head>
<body>
<div>{side_bar}</div>
<div>{page_content}</div>
<div>{right_col}</div>
</body>
</html>
2) Load another view in your view: (assumes you menu is a view not a controller) Something like this:
<?php $this->load->view('menu_view'); ?>
3) PHP Includes: exactly how you would do it in plain PHP (just include a url which points to a controller which returns a menu), Something like this:
<?php include("/common/sidebar"); ?>
Codeigniter will render that page and then include it.
4) AJAX.. i use this if the content in the "template" content is less important, like banners, suggested related item lists and such.
Use PHP to generate a static HTML page, such as side_bar.html...
Then you can include it on other pages.
You could look into HMVC. It's especially suited for "widget"-type areas like you are talking about.
Essentially what you will do is create two full MVC structures - one for your sidebar and right column, including a controller, a model(if required), and a partial view. Then, you can call this controller directly from the main view to pull the required content in to the page.
To actually call it from within a view, just place the following in the markup wherever you want the sidebar to appear:
<?php echo modules::run('module/sidebar/index'); ?>
The index isn't required, but I put it there to demonstrate that you can call different methods using modules::run(). You can also pass an unlimited number of parameters to modules::run().
In code igniter, there is an optional third parameter to $this->load->view that lets you return a rendered view as a string, which can in turn be used for assignment. What you can do is create a master template, that has all the common parts, as a very simplified example:
<html>
<head>
</head>
<body>
<?php echo $sidebar; ?>
<?php echo $content; ?>
<?php echo $right_column; ?>
</body>
</html>
Then you can create a private function in your controller to populate the dynamic content of your common parts, and combine them with your content and master template:
private function BuildTemplate($view, $data) {
// Generate sidebar content
$sidebar_data['...'] = 'blah blah';
$master_data['sidebar'] = $this->load->view('sidebar', $sidebar_data, true);
// Generate right column data
$right_data['...'] = 'blah blah';
$master_data['right_column'] = $this->load->view('right_column', $right_data, true);
// Now load your content
$master_data['content'] = $this->load->view($view, $data, true);
// Merge it into the master template and return it
return $this->load->view('master' $master_data, true);
}
Then in your appropriate controller method:
public function index() {
$data['...'] = 'blah';
echo $this->BuildTemplate('index', $data);
}
Which will pull everything together for you. You can optionally add extra arguments to BuildTemplate if you want to add things like page specific titles or scripts.
I'm not sure if your problem is in the view, or in the (dynamic) data to be shown in the (common parts of) that view.
If it's the later (as seems to suggest the phrase 'I don't want to recode the same bits to get the data in every controller'), then you have several options. For example.
Put the logic to get the 'common' data in some function outside the controller, as a helper or inside some model, and call it from your controllers.
Make your controllers inherit your own custom controller, that implements that data gathering function.
Refactor your two controllers into a single controller, with different functions for each scenario.
1-Create a custom library class in library folder with the below code
if (!defined('BASEPATH')) exit('No direct script access allowed');
class LoadView{
function __construct(){
$this->CI =& get_instance();
}
function load_view($page){
$this->CI->load->view('header');
$this->CI->load->view('sidebar');
$this->CI->load->view($page);
$this->CI->load->view('footer');
}
}
2-Now load this library in your controller like this
$this->load->library('loadview');
3-Now call the library method and simply insert your page name and you don't have to include header,sidebar and footer again and again as they will be dynamically included by your library.
$this->loadview->load_view('about.php');

Categories