How to run an action of controller file from .ctp file? - php

I want to call an action along with its .ctp file of a controller file from another .ctp file.
for e.g.
users_controller.php has an action called list_category() and I want to call it from /app/views/pages/index.ctp file. Not just call list_category but also want to show its html output(I mean also list_category.ctp should be rendered).
Thanks.

Create an element, for instance list_category.ctp.
In the element use requestAction to get the data:
<?php
$categories = $this->requestAction('/users/list_categories');
?>
<?php foreach($categories as $category): ?>
<?php // Your display code goes here ?>
<?php endforeach; ?>
In your controller make sure you return the data you want.
<?php
function list_categories() {
return $this->User->Category->find('all');
}
?>
You can reuse the code for your list_category.ctp view.
There is an overhead when using requestAction but it is often less than people believe.

Can you do that with routing? I'm not sure of the syntax off the top of my head but I think you can specify that method that the controller runs when you land on that page

It seems wrong, what is it that you're trying to accomplish? How about elements?

How about calling the controller from your main controller, then pass its results to your layout. Finally use an element to render the output there and also use the element to render the output on that other controller too. That way you don't have duplicate layouts. Just one element used by two controllers.
This is very similar to the way Rails creates its layouts when you 'bake' them. It creates an equivalent of a element to use in the add and edit layouts.

This can be done with requestAction, but be aware, that it's expensive and you should be careful with it.

Related

opencart controller and children

I have two questions:
In a controller ControllerMainIndex in opencart we do define
$this->children = array("common/footer");
Then how should I utilize it in the main/index.tpl file?
It is a little bit vague for me. We have told the controller to get footer but in the main file how should we specify their position?
Second question, I create controller ControllerMasterNewPage and then in I $this->render() (after setting the template to "master/newpage.tpl").
But how should I access this controller? I means what should be typed in the browser for this controller to be process and have output?
1) Just call <?php echo $footer ?> it will output that child content
2) http://example.com/index.php?route=path/MasterNewPage/actionName
e.g.: We have file in {root}/catalog/controller/product/category.php (class name ControllerProductCategory), call it: http://example.com/index.php?route=product/category

where is $content variable declared in Yii?

I am using Yii Framework. In the view, main.php, there is a reference to the $content block
<?php echo $content; ?>
I could not find it anywhere in the model or elsewhere in the demo project. Can someone shed light on this? Or may be this variable is never declared? I have not modified the demo project yet.
The $content value in layout files contains the rendered content of the template specified as the first attribute of the render command. (It's automatically created so I wouldn't use "content" as an additional variable name or it could cause confusion.) The variables that you pass as an additional array argument in the render statement are made available to the template you are calling, not to the layout.
If you have nested layouts, the value of $content cascades from parent to child.
All your controllers are derived from CController class. CController has a function named render which you call it for rendering your views. It works like this:
beforeRender is called.
renderPartial is called on your view file, and its output is stored in $output.
renderFile is called on the layout file, with a parameter named content like this:
$this->render(layoutFile, array('content'=>$output));
So the $content is coming from here. You can see the actual code here: Source code, and documentation here: Documentation
Found answer from Yii Documentation / Layouts,
For example, a layout may contain a header and a footer, and embed the
view in between, like this:
......header here......
<?php echo $content; ?>
......footer here......
where $content stores the rendering result of the view.
It is indeed all the text in one of the view (in my case index.php). $content basically takes the content of view. It is not declared anywhere and it is be default. As the answer said, you should not use declare/use $content in your code.
I think its being set from the controller which is calling this view.
In the controller look for something like the following
$this->render('main', array('content'=>"something here"));

Zend bootstrap, including javascript files for certain pages only

I'm loading javascript files in the bootstrap as usual, but there's a file that I want to have included only if it's a page that has a form
->appendFile('http://myurl.com/js/formscript.js');
Is there a way to detect the page being loaded, from the bootstrap so I can decide whether or not to include this file?
I thought about passing a variable from the Form to the view, and then checking for that variable in the bootstrap, but it's not working.
This would be in my form
$layout = new Zend_Layout();
$view = $layout->getView();
$view->formscript = true;
and this would be in my bootstrap
if ($view->formscript)
but var_dump($view->formscript) give me null, so any other ideas to activate js files only in specific conditions?
To include javascript files in a particular pages alone, add the following code in those pages(I mean view scripts - *.phtml).
<?php
$this->headScript()->appendFile('http://myurl.com/js/formscript.js');
?>
Similarly, to add CSS files to a particular page, do the following.
<?php
$this->headLink()->appendStylesheet('http://myurl.com/styles.css');
?>
It is possible, but you do not need your bootstrap. You can just access the variable from your layout:
//form
$view = Zend_Layout::getMvcInstance()->getView();
$view->formscript = TRUE;
//layout
if($this->formscript)
{
$this->headScript()->appendFile('http://myurl.com/js/formscript.js');
}
echo $this->headScript();
Do not use getView() in your form as it will return the view object for the form, not for your application. This has tripped me up more than a couple of times >.>
Your idea to set a flag - something like $view->hasForm - in your view seems like a pretty reasonable approach. But as others have noted, it shouldn't be the form itself that attempts to set the flag since it doesn't really have access to view object until rendering time.
Instead, wherever you place a form into your view - probably in a controller, perhaps even in a front controller plugin - simply set your flag there.
Then your view script or layout can call $this->headScript()->appendFile() if the flag has been set.
Why not move over appendFile() to your form class (of course if you use Zend_Form), you would be sure that your JS line will be created only in the same time as your form. The place for this line is good in init() as well as in render()
class Your_Form extends Zend_Form {
public init(){
$this->getView()->appendFile('http://myurl.com/js/formscript.js');
[...]
}
}

What's the proper MVC way to do this....?

Quick question about general MVC design principle in PHP, using CodeIgniter or Kohana (I'm actually using Kohana).
I'm new to MVC and don't want to get this wrong... so I'm wondering if i have tables:
categories, pages, notes
I create a separate controller and view for each one...? So people can go to
/category/#
/page/#
/note/#
But then lets say I want to also be able to display multiple notes per page, it would be bad to call the note view in a loop from the page view. So should I create some kind of a function that draws the notes and pass variables to that function from the note view and from a loop in the page view? Would this be the best way to go about it, if not how else should I do it...?
Thanks,
Serhiy
Yes, instead of just passing 1 entity (category, page, note) to your view, pass a list of entities. With a loop inside the view, you can display the whole list.
That view may call another one (or a function) that know how to display one entry.
I would personally have a "show" method for one item and a "list" method for multiple. In your controller you can say something like $page_data['note'] = get_note(cat_id,page_id) for the "show" method and $page_data['notes'] = get_all_notes(cat_id) for the "list" method.
Then in your view, you loop over the $page_data['notes'] and display HTML for each one. If the list view is using the same "note" HTML as the "show" view, create a template or function to spit out the HTML given a note:
// In your "list" view
foreach($n in $page_data['notes']){
print_note_html($n)
}
//In your "show" view
print_note_html($n)
The print_note_html function can be a helper method accessible by all views for Notes. Make sense?
You can loop in the View. The View is allowed can also access the model in MVC. See: http://www.phpwact.org/pattern/model_view_controller
You don't need to have a controller (or model) for each table.
In CodeIgniter I create a separate helper file where I put functions that return the markup for UI elements that may need to be included multiple times in the one view.
In your example, I would create a function to return the markup for a note.
application/helpers/view_helper.php
function note($note)
{
return '<div class="note">' .
'<h2>' . $note->title . '</h2>' .
'<p>' . $note->contents . '</p></div>';
}
I would normally auto-load this helper file. And then in the view I would do something like this.
echo note($note);
For a list of notes in a view, I would iterate the list calling this function.
<div class="note-list">
<?php foreach ($notes as $note) : ?>
<?php echo note($note); ?>
<?php endforeach; ?>
</div>
I found that including a view many times in another view was slow. Thats why I did it this way.
Edit
I just dug into the CodeIgniter Loader class and sure enough a PHP include is being done every time you call
$this->load->view('view_name');
This means that if you use this method to display a list of 20 notes, you're going to be doing 20 separate includes.

CakePHP View including other views

I have a CakePHP application that in some moment will show a view with product media (pictures or videos) I want to know if, there is someway to include another view that threats the video or threats the pictures, depending on a flag. I want to use those "small views" to several other purposes, so It should be "like" a cake component, for reutilization.
What you guys suggest to use to be in Cake conventions (and not using a raw include('') command)
In the interest of having the information here in case someone stumbles upon this, it is important to note that the solution varies depending on the CakePHP version.
For CakePHP 1.1
$this->renderElement('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.thtml, where $flag will have the value of whatever you pass to it.
For CakePHP 1.2
$this->element('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.ctp, where $flag will have the value of whatever you pass to it.
In both versions the element will have access to all the data the view has access to + any values you pass to it. Furthermore, as someone pointed out, requestAction() is also an option, but it can take a heavy toll in performance if done without using cache, since it has to go through all the steps a normal action would.
In your controller (in this example the posts controller).
function something() {
return $this->Post->find('all');
}
In your elements directory (app/views/element) create a file called posts.ctp.
In posts.ctp:
$posts = $this->requestAction('posts/something');
foreach($posts as $post):
echo $post['Post']['title'];
endforeach;
Then in your view:
<?php echo $this->element('posts'); ?>
This is mostly taken from the CakePHP book here:
Creating Reusable Elements with requestAction
I do believe that using requestAction is quite expensive, so you will want to look into caching.
Simply use:
<?php include('/<other_view>.ctp'); ?>
in the .ctp your action ends up in.
For example, build an archived function
function archived() {
// do some stuff
// you can even hook the index() function
$myscope = array("archived = 1");
$this->index($myscope);
// coming back, so the archived view will be launched
$this->set("is_archived", true); // e.g. use this in your index.ctp for customization
}
Possibly adjust your index action:
function index($scope = array()) {
// ...
$this->set(items, $this->paginate($scope));
}
Your archive.ctp will be:
<?php include('/index.ctp'); ?>
Ideal reuse of code of controller actions and views.
For CakePHP 2.x
New for Cake 2.x is the abilty to extend a given view. So while elements are great for having little bits of reusable code, extending a view allows you to reuse whole views.
See the manual for more/better information
http://book.cakephp.org/2.0/en/views.html#extending-views
Elements work if you want them to have access to the same data that the calling view has access to.
If you want your embedded view to have access to its own set of data, you might want to use something like requestAction(). This allows you to embed a full-fledged view that would otherwise be stand-alone.
I want to use those "small views" to
several other purposes, so It should
be "like" a cake component, for
reutilization.
This is done with "Helpers", as described here. But I'm not sure that's really what you want. The "Elements" suggestion seems correct too. It heavily depends of what you're trying to accomplish. My two cents...
In CakePHP 3.x you can simple use:
$this->render('view')
This will render the view from the same directory as parent view.

Categories