php Codeigniter:构建局部视图的最佳方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3675135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Codeigniter: Best way to structure partial views
提问by Gary Green
How would you structure the below page in Codeigniter?
您将如何在 Codeigniter 中构建以下页面?
I thought about creating seperate controllers for each section
我想为每个部分创建单独的控制器
- Left nav
- Content nav
- Login name
- Leaderboard
- 左导航
- 内容导航
- 登录名
- 排行榜
Excluding the content section (as this changes depending on the link on the left nav and content nav used as a kinda sub-menu). All the other sections remain roughly the same
不包括内容部分(因为这取决于左侧导航上的链接和用作有点子菜单的内容导航)。所有其他部分保持大致相同
I thought about doing:
我想过这样做:
Class User_Profile extends Controller
{
function index()
{
$this->load_controller('Left_Nav');
$this->load_controller('Content_Nav');
$this->load_controller('Login_Name');
$this->load_controller('Leaderboard', 'Board');
$this->Left_Nav->index(array('highlight_selected_page' => 'blah'));
$this->load('User');
$content_data = $this->User->get_profile_details();
$this->view->load('content', $content_data);
$this->Login_Name->index();
$this->Board->index();
}
}
Obviously this load_controller
does not exist but this functionaility would be useful. The controller for each section gets the data required from the model and then loads the page through $this->view->load()
显然这load_controller
不存在,但此功能会很有用。每个部分的控制器从模型中获取所需的数据,然后通过加载页面$this->view->load()
It could be a headache to have this code in all the left nav links like News, Users, About Us, etc.. But then again not every nav link has all those sections so I need that flexability of having the sections as a "partial view"
在所有左侧导航链接(如新闻、用户、关于我们等)中使用此代码可能会令人头疼。但是,并非每个导航链接都包含所有这些部分,因此我需要将这些部分作为“部分看法”
Can anyone suggest a better way of doing this?
任何人都可以提出更好的方法吗?
采纳答案by slikts
I can't vouch that this is the best approach, but I create a base controller like this:
我不能保证这是最好的方法,但我创建了一个这样的基本控制器:
class MY_Controller extends CI_Controller {
public $title = '';
// The template will use this to include default.css by default
public $styles = array('default');
function _output($content)
{
// Load the base template with output content available as $content
$data['content'] = &$content;
$this->load->view('base', $data);
}
}
The view called 'base' is a template (a view that includes other views):
名为“base”的视图是一个模板(包含其他视图的视图):
<?php echo doctype(); ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<?php $this->load->view('meta'); ?>
</head>
<body>
<div id="wrapper">
<?php $this->load->view('header'); ?>
<div id="content">
<?php echo $content; ?>
</div>
<?php $this->load->view('footer'); ?>
</div>
</body>
</html>
What this achieves is that every controller wraps its output in the base template, and that views have valid HTML instead of opening tags in one view and closing in another. If I'd like a specific controller to use a different or no template, I could just override the magic _output()
method.
这实现的是每个控制器将其输出包装在基本模板中,并且视图具有有效的 HTML,而不是在一个视图中打开标签并在另一个视图中关闭。如果我想要一个特定的控制器使用不同的模板或不使用模板,我可以覆盖魔法_output()
方法。
An actual controller would look like this:
实际控制器如下所示:
class Home extends MY_Controller {
// Override the title
public $title = 'Home';
function __construct()
{
// Append a stylesheet (home.css) to the defaults
$this->styles[] = 'home';
}
function index()
{
// The output of this view will be wrapped in the base template
$this->load->view('home');
}
}
Then I could use its properties in my views like this (this is the 'meta' view that populates the <head>
element):
然后我可以像这样在我的视图中使用它的属性(这是填充<head>
元素的“元”视图):
echo "<title>{$this->title}</title>";
foreach ($this->styles as $url)
echo link_tag("styles/$url.css");
I like my approach because it respects the DRY principle and the header, footer and other elements get included just once in the code.
我喜欢我的方法,因为它尊重 DRY 原则,并且在代码中只包含一次页眉、页脚和其他元素。
回答by alvincrespo
@Reinis answer probably hit the spot correctly for older versions of CI less than 2.0 however alot has changed since then, so I thought I'd answer this question with an up to date method of what I've done.
@Reinis 的回答对于低于 2.0 的旧版本 CI 可能正确地找到了位置,但是从那时起发生了很多变化,所以我想我会用我所做的最新方法来回答这个问题。
Most of it is similar to @Reinis method and also described here:http://codeigniter.com/wiki/MY_Controller_-_how_to_extend_the_CI_Controller
大部分类似于@Reinis 方法,也在这里描述:http://codeigniter.com/wiki/MY_Controller_-_how_to_extend_the_CI_Controller
However here are the updates ive done:
但是,这里是我所做的更新:
Step 1: Create a MY_Controller.php file and store it in /application/core
步骤1:创建一个MY_Controller.php文件并将其存储在/application/core
Step 2: In your MY_Controller.php file put in the following contents:
第 2 步:在您的 MY_Controller.php 文件中输入以下内容:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
}
function _output($content)
{
// Load the base template with output content available as $content
$data['content'] = &$content;
echo($this->load->view('base', $data, true));
}
}
Step 3: Create a sample controller to base off of MY_Controller.php, in this case I will create a welcome.php controller inside of application/controllers/ with the following content:
第 3 步:创建一个基于 MY_Controller.php 的示例控制器,在这种情况下,我将在 application/controllers/ 内创建一个welcome.php 控制器,其内容如下:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends MY_Controller {
function __construct()
{
parent::__construct();
}
public function index()
{
$this->load->view('welcome_message');
}
}
Once you have these controllers set, do the following:
设置好这些控制器后,请执行以下操作:
Step 4: Create a base view inside of /application/views and name the file base.php, the content of the file should be similar to this:
第四步:在/application/views里面创建一个base view,并将文件命名为base.php,文件内容应该是这样的:
<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title></title>
<link rel="stylesheet" href="<?php echo base_url(); ?>stylesheets/reset.css" media="screen" />
</head>
<body>
<div id="section_main">
<div id="content">
<?php echo $content; ?>
</div>
</div>
<?php $this->load->view('shared/scripts.php'); ?>
</div>
</body>
</html>
Step 5: Create another view in /application/views and name this view welcome_message.php, the content of this file will be:
第五步:在/application/views中创建另一个视图,并将该视图命名为welcome_message.php,该文件的内容为:
<h1>Welcome</h1>
Once, all this is complete, you should see the following output:
所有这些都完成后,您应该会看到以下输出:
<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title></title>
<link rel="stylesheet" href="http://somedomain.local/stylesheets/reset.css" media="screen" />
</head>
<body>
<!-- BEGIN: section_main -->
<div id="section_main">
<div id="content">
<h1>Welcome</h1>
</div>
</div>
<!-- END: section_main -->
<script src="/path/to/js.js"></script>
</div>
</body>
</html>
As you can see <h1>Welcome</h1>
was put into the base template.
如您所见,<h1>Welcome</h1>
已放入基本模板中。
Resources:
资源:
- Obviously @Reinis initial response
- http://codeigniter.com/wiki/Extending_Controller_with_masterpage_template_funtionality
- 显然@Reinis 最初的回应
- http://codeigniter.com/wiki/Extending_Controller_with_masterpage_template_funtionality
Hope this helps anyone else coming across this technique.
希望这可以帮助其他人遇到这种技术。
回答by Phil Sturgeon
My Template library can handle all of this. You create a single (or multiple) layout file(s) that contain the partials and a tag for where the main body content will go.
我的模板库可以处理所有这些。您创建一个(或多个)布局文件,其中包含部分和主体内容所在位置的标签。
Syntax as simple as:
语法简单如:
// Set the layout: defaults to "layout" in application/views/layout.php
$this->template->set_layout('whatever')
// Load application/views/partials/viewname as a partial
$this->template->set_partial('partialname', 'partials/viewname');
// Call the main view: application/views/bodyviewname
$this->template->build('bodyviewname', $data);
Simples right?
简单对吗?
Put some of that into MY_Controller and its even easier.
将其中的一些放入 MY_Controller 中,它甚至更容易。
回答by Phil Sturgeon
I like what Phil Sturgeon mentioned. Although it's considered as very complicated i really liked template structure that magento have.
我喜欢 Phil Sturgeon 提到的。虽然它被认为非常复杂,但我真的很喜欢 magento 的模板结构。
Inspired with that way of structuring i made my logic, (which is not great at all but it's simple as it can be,. and perhaps maybe i could override ->view loader and make it accept some kind of object as a template name and than load the structure as required)
受这种结构方式的启发,我制定了我的逻辑,(这根本不是很好,但它很简单,也许我可以覆盖 -> 视图加载器并使其接受某种对象作为模板名称和比根据需要加载结构)
first: This approach must be used very responsibly (you mus prepare data in controller/method that your templates require!
第一:必须非常负责任地使用这种方法(您必须在控制器/方法中准备模板所需的数据!
second: Template needs to be prepared and structured properly.
第二:模板需要准备好,结构合理。
This is what i do:
这就是我所做的:
in every controller i have attribute of Array type, something like this:
class Main extends CI_Controller { public $view = Array( 'theend' => 'frontend', 'layout' => '1column', 'mainbar' => array('content','next template file loaded under'), 'sidebar' => array('generic','next template file loaded under'), 'content' => '', );
In every method for which i want to use previous structure, and if i want to change it a bit i write it like this:
public function index() { $data['view'] = $this->view; // i take/load global class's attribute $data['view']['mainbar'] = Array('archive','related_posts'); // i change mainbar part of it // i add/load data that i need in all those templates that are needed $data['view'] also my using same Array $data['my_required_data_that_i_use_in_template_files'] = 1; $this->load->view('main',$data); // }
在每个控制器中,我都有数组类型的属性,如下所示:
class Main extends CI_Controller { public $view = Array( 'theend' => 'frontend', 'layout' => '1column', 'mainbar' => array('content','next template file loaded under'), 'sidebar' => array('generic','next template file loaded under'), 'content' => '', );
在我想使用以前结构的每种方法中,如果我想稍微改变它,我会这样写:
public function index() { $data['view'] = $this->view; // i take/load global class's attribute $data['view']['mainbar'] = Array('archive','related_posts'); // i change mainbar part of it // i add/load data that i need in all those templates that are needed $data['view'] also my using same Array $data['my_required_data_that_i_use_in_template_files'] = 1; $this->load->view('main',$data); // }
thirdIn /application/view folder i have structure like
第三在 /application/view 文件夹中,我的结构类似于
/view/main.php <-- which basically just determines which side's wrapper of web to load (frontend or backend or some other)
/view/frontend/wrapper.php
/view/backend/wrapper.php
/view/mobile/wrapper.php <-- this wrappers are again another level of structuring for ex:
/view/backend/layouts/ <-- inside i have templates different layouts like 1column.php 2columns-left (have left side is narrow one),2columns-right,3columns... etc...
/view/backend/mainbar/ <-- inside i have templates for mainbar in pages
/view/backend/mainbar/.../ <-- in the same way it's possible to add folders for easily grouping templates for example for posts so you add for example
/view/backend/mainbar/posts/ <-- all templates for creating, editing etc posts...
/view/backend/sidebar/ <-- inside i have templates for sidebar in pages
/view/backend/...other special cases.... like dashboard.php
forthfile in /app/view/main.php looks something like:
提出在/app/view/main.php文件看起来是这样的:
if ($view['theend'] == "frontend")
{
$this->load->view('/frontend/wrapper');
} elseif ($view['theend'] == "backend")
{
$this->load->view('/backend/wrapper');
}
fifthwrapper is simple some php in structured HTML where you have head (loading html headers, title etc...) header/headers (loading in headers if there are any in passed $data['view']['headers'] variable/array) layout (loads in layout file that simply have new html structured file with next level of loading files) footer/footers (loading in footers if there are any in passed $data['view']['footers'] variable) scripts (loading inscripts like analytics/facebook scripts just before tag)
第五个包装器很简单,结构化 HTML 中的一些 php,你有头部(加载 html 标题,标题等...)标题/标题(如果有任何传入的 $data['view']['headers'] 变量,则加载标题/array) 布局(在布局文件中加载,只有新的 html 结构化文件和下一级加载文件)页脚/页脚(如果传入的 $data['view']['footers'] 变量中有任何内容,则加载页脚)脚本(在标记之前加载分析/facebook 脚本之类的内嵌脚本)
sixthSo in the same way, layout would be also loading in mainbar/sidebar content that is specified in public $view = Array(....)
第六所以以同样的方式,布局也将加载到公共 $view = Array(....) 中指定的主栏/侧栏内容中
If i need in some method, i simply override part of public $view = Array(...) attribute, and i override just part that is different.
如果我需要某种方法,我只需覆盖公共 $view = Array(...) 属性的一部分,而我只覆盖不同的部分。
it's done something like this:
它做了这样的事情:
public function index()
{
$data['view'] = $this->view; // i take/load global class's attribute
$data['view']['mainbar'] = Array('archive','related_posts'); // i change mainbar part of it
// i add/load data that i need in all those templates that are needed $data['view'] also my using same Array $data['my_required_data_that_i_use_in_template_files'] = 1;
$this->load->view('main',$data); //
}
FINALLY Load goes like this:
最终加载是这样的:
$this->load->view('main',$data); <-- Loads /app/view/main.php and passes $data $data has node 'view' ($data['view']) and in it it has sub nodes which determines other important things like: what is the end, what layout, what headers, what footers etc...
Using defined data in $data['view']['theend'] it loads proper wrapper
- Again using data in $data['view']['layout'] further in wrapper it loads other, deeper structures like layout...
- layout, uses same $data['view']['mainbar'], $data['view']['sidebar'] and catch other important parts to load like mainbar templates, sidebar templates ...
$this->load->view('main',$data); <-- 加载 /app/view/main.php 并传递 $data $data 有节点 'view' ($data['view']) 并且它有子节点,它决定了其他重要的事情,比如:什么是结束,什么布局,什么页眉,什么页脚等等...
使用 $data['view']['theend'] 中定义的数据,它会加载适当的包装器
- 再次使用 $data['view']['layout'] 中的数据进一步在包装器中加载其他更深的结构,如布局......
- 布局,使用相同的 $data['view']['mainbar'], $data['view']['sidebar'] 并捕获其他重要部分以加载,如主栏模板、侧边栏模板......
That is about it...
就是这样...
p.s. I'm so sorry for not using numbers, but stackoverflow system is so strange that instead of showing 3. it shows me 1.. as you see i had some nested lists...
ps我很抱歉没有使用数字,但是stackoverflow系统太奇怪了,而不是显示3。它向我显示了1..正如你看到的,我有一些嵌套列表......
回答by Ross
have you considered templates? There are many decent ones available with a little searching - check the CI wiki.
你考虑过模板吗?只需稍加搜索,就可以找到许多不错的选择 - 检查 CI wiki。
templates do more or less exactly what you are after. You define one master template and "sections", and these are loaded for you each time
模板或多或少完全符合您的要求。您定义一个主模板和“部分”,并且每次都会为您加载这些
don't want to plug too much so this might get you started - template libraries in CI
不想插入太多,所以这可能会让你开始 - CI 中的模板库
回答by rkj
I would make a MY_Controller to take care of all this. You can top it with a layout(template)/navigation library to generate all the layouts, navigation, showing/highlighting selected menu item, loading views etc.
我会制作一个 MY_Controller 来处理这一切。您可以使用布局(模板)/导航库来生成所有布局、导航、显示/突出显示所选菜单项、加载视图等。
I'd say it's not the right way to do it, if you're using a controller for each page section. You can to make use of views and nested views for that.
如果您为每个页面部分使用控制器,我会说这不是正确的方法。您可以为此使用视图和嵌套视图。
回答by Fanis Hatzidakis
What I've done (in Kohana 2) is have the 1 template with all the sub sections (like left menu, top header), and a single controller that populates the variables that will be replaced in the template.
我所做的(在 Kohana 2 中)有 1 个模板,其中包含所有子部分(如左侧菜单、顶部标题),以及一个填充将在模板中替换的变量的控制器。
Then, the variables for every sub-section can be generated by functions called in the controller itself. You can also have those functions be in a separate controller class's constructor, with every controller of yours extending that one so they're automatically ran and set as class variables for easy access.
然后,每个子部分的变量可以由控制器本身调用的函数生成。您还可以将这些函数放在单独的控制器类的构造函数中,您的每个控制器都扩展那个,以便它们自动运行并设置为类变量以便于访问。
For slightly nicer templates you can have the subsections in separate files, and the big template include them:
对于稍微好一点的模板,您可以将小节放在单独的文件中,大模板包含它们:
<?php include 'leftMenu.php'; ?>