YII Framework学习教程-YII的V-view的基本使用和实现原理-2011-11-16

  MVC的view层的功能一样就是负责显示,可以认为是用户的输入输出。是用户直接使用操作的地方。大部分功能就是把数据如何更有好的展示给用户,如何更容易的让用户操作,输入反馈数据,完成交互功能。

 V(view)层和C(controller)控制器是紧密相连的。C在需要的时候调用V来显示数据,也可以在需要的时候调用V来获取用户的数据。如果C是灵魂,那么V就是一个肉体。两者是不可分割的一部分。

 1.yii中view的存储位置以及规则

  打开testwebap项目

/www/yii_dev/testwebap/protected# tree views
views
├── layouts
│   ├── column1.php
│   ├── column2.php
│   └── main.php
├── site
│   ├── contact.php
│   ├── error.php
│   ├── index.php
│   ├── login.php
│   └── pages
│       └── about.php
├── testTest
│   ├── action1.php
│   ├── action2.php
│   ├── action3.php
│   └── index.php
└── user
    ├── admin.php
    ├── create.php
    ├── _form.php
    ├── index.php
    ├── _search.php
    ├── update.php
    ├── userformtest.php
    ├── _view.php
    └── view.php


5 directories, 21 files 

/www/yii_dev/testwebap/protected# tree modules/
modules/
└── testmod
    ├── components
    ├── controllers
    │   └── DefaultController.php
    ├── messages
    ├── models
    ├── TestmodModule.php
    └── views
        ├── default
        │   ├── index.php
        └── layouts


8 directories, 1 files


可以看到:

一般在项目的protected的views文件夹中。如果有modules,放在protected/modules/views中.

结构一般view下对应的是以contoller的名字命名的文件夹。下面存放此contoller使用的相应文件。


2.Controller是如何调用View。

打开SiteController.php

/**
	 * This is the default 'index' action that is invoked
	 * when an action is not explicitly requested by users.
	 */
	public function actionIndex()
	{
		// renders the view file 'protected/views/site/index.php'
		// using the default layout 'protected/views/layouts/main.php'
		$this->render('index');
	}

可以看到是通过

$this->render函数来调用view。

3。Controller调用View的实现原理

打开render方法看一下。

public function render($view,$data=null,$return=false)
	{
		if($this->beforeRender($view))
		{
			$output=$this->renderPartial($view,$data,true);
			if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
				$output=$this->renderFile($layoutFile,array('content'=>$output),true);
			$this->afterRender($view,$output);
			$output=$this->processOutput($output);
			if($return)
				return $output;
			else
				echo $output;
		}
	}
	protected function beforeRender($view)
	{
		return true;
	}
	protected function afterRender($view, &$output)
	{
	}

public function renderPartial($view,$data=null,$return=false,$processOutput=false)
	{
		if(($viewFile=$this->getViewFile($view))!==false)
		{
			$output=$this->renderFile($viewFile,$data,true);
			if($processOutput)
				$output=$this->processOutput($output);
			if($return)
				return $output;
			else
				echo $output;
		}
		else
			throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
				array('{controller}'=>get_class($this), '{view}'=>$view)));
	}

	public function getViewFile($viewName)
	{
		if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
			return $viewFile;
		$moduleViewPath=$basePath=Yii::app()->getViewPath();
		if(($module=$this->getModule())!==null)
			$moduleViewPath=$module->getViewPath();
		return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath);
	}
	public function getLayoutFile($layoutName)
	{
		if($layoutName===false)
			return false;
		if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false)
			return $layoutFile;
		if(empty($layoutName))
		{
			$module=$this->getModule();
			while($module!==null)
			{
				if($module->layout===false)
					return false;
				if(!empty($module->layout))
					break;
				$module=$module->getParentModule();
			}
			if($module===null)
				$module=Yii::app();
			$layoutName=$module->layout;
		}
		else if(($module=$this->getModule())===null)
			$module=Yii::app();
		return $this->resolveViewFile($layoutName,$module->getLayoutPath(),Yii::app()->getViewPath(),$module->getViewPath());
	}
	public function resolveViewFile($viewName,$viewPath,$basePath,$moduleViewPath=null)
	{
		if(empty($viewName))
			return false;
		if($moduleViewPath===null)
			$moduleViewPath=$basePath;
		if(($renderer=Yii::app()->getViewRenderer())!==null)
			$extension=$renderer->fileExtension;
		else
			$extension='.php';
		if($viewName[0]==='/')
		{
			if(strncmp($viewName,'//',2)===0)
				$viewFile=$basePath.$viewName;
			else
				$viewFile=$moduleViewPath.$viewName;
		}
		else if(strpos($viewName,'.'))
			$viewFile=Yii::getPathOfAlias($viewName);
		else
			$viewFile=$viewPath.DIRECTORY_SEPARATOR.$viewName;
		if(is_file($viewFile.$extension))
			return Yii::app()->findLocalizedFile($viewFile.$extension);
		else if($extension!=='.php' && is_file($viewFile.'.php'))
			return Yii::app()->findLocalizedFile($viewFile.'.php');
		else
			return false;
	}

public function renderFile($viewFile,$data=null,$return=false)
	{
		$widgetCount=count($this->_widgetStack);
		if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile))
			$content=$renderer->renderFile($this,$viewFile,$data,$return);
		else
			$content=$this->renderInternal($viewFile,$data,$return);
		if(count($this->_widgetStack)===$widgetCount)
			return $content;
		else
		{
			$widget=end($this->_widgetStack);
			throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.',
				array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget))));
		}
	}


public function renderInternal($_viewFile_,$_data_=null,$_return_=false)
	{
		// we use special variable names here to avoid conflict when extracting data
		if(is_array($_data_))
			extract($_data_,EXTR_PREFIX_SAME,'data');
		else
			$data=$_data_;
		if($_return_)
		{
			ob_start();
			ob_implicit_flush(false);
			require($_viewFile_);
			return ob_get_clean();
		}
		else
			require($_viewFile_);
	}




	public function processOutput($output)
	{
		Yii::app()->getClientScript()->render($output);
		// if using page caching, we should delay dynamic output replacement
		if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
		{
			$output=$this->processDynamicOutput($output);
			$this->_dynamicOutput=null;
		}
		if($this->_pageStates===null)
			$this->_pageStates=$this->loadPageStates();
		if(!empty($this->_pageStates))
			$this->savePageStates($this->_pageStates,$output);
		return $output;
	}
	public function processDynamicOutput($output)
	{
		if($this->_dynamicOutput)
		{
			$output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
		}
		return $output;
	}
	protected function replaceDynamicOutput($matches)
	{
		$content=$matches[0];
		if(isset($this->_dynamicOutput[$matches[1]]))
		{
			$content=$this->_dynamicOutput[$matches[1]];
			$this->_dynamicOutput[$matches[1]]=null;
		}
		return $content;
	}
 
lic function findLocalizedFile($srcFile,$srcLanguage=null,$language=null)
	{
		if($srcLanguage===null)
			$srcLanguage=$this->sourceLanguage;
		if($language===null)
			$language=$this->getLanguage();
		if($language===$srcLanguage)
			return $srcFile;
		$desiredFile=dirname($srcFile).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.basename($srcFile);
		return is_file($desiredFile) ? $desiredFile : $srcFile;
	}

以上已经按照颜色传递做了简单的流程说明。你应该大体了解实现方法了。上面主要标记的是view文件的引用方法和相应的数据的传递方式。应该不难理解。当然还有附属的layout,widget,页面缓存和国际化等等处理。可以自己追踪代码看看具体的实现方法这里只是简单说明。便于理解。明白在controller中调用render可以解析到指定的view文件,并把数据传递过去。我们做的就是在view中如何展示。


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值