Zend Framework - Zentraler View

ZodiacXP

Erfahrenes Mitglied
One view to rule them all :P Das habe ich vor.

Da sich das "Rahmendesign" nicht ändert soll es einen View geben, der dementsprechend eingebunden wird. Innerhalb dessen kommt dann eine Zeile wie:
PHP:
<?= $this->content; ?>
wobei $this->content den eigentlichen View zur angeforderten Seite anzeigen soll.

Im Netz wird oft auf Helper verwiesen demnach habe ich diese Lösung gefunden, bin damit aber noch nicht ganz zufrieden:
PHP:
class IndexController extends Zend_Controller_Action
{
	public function indexAction()
	{
	}
	
	public function __construct($request, $response, $invokeArgs)
	{
		parent::__construct($request, $response, $invokeArgs);
		$this->_helper->viewRenderer->renderBySpec('design', array('controller' => 'index'));
	}
}
 
Ah ok. Da blick ich durch - hat geklappt.
Und wenn ich einzelne Designbausteine habe die nacheinander im Content seien sollen (zum Beispiel Einträge), dann verwende ich ein View oder ein Layout?

Beispiel: Aus dem Model kommen mehrere Zeilen mit Daten (Überschrift und Text). Diese sollen in den Bausteinen abgelegt und an den Content angehängt werden.
Layouts scheinen mir da sehr statisch zu sein und Zend_View (http://framework.zend.com/manual/de/zend.view.introduction.html) hat mir zu viel PHP im Template selbst.
 
Hi,

wenn du für bestimmte Model-Outputs unterschiedliche Design-Möglichkeiten haben möchtest, solltest du tatsächlich Helper verwenden. Allerdings gibts für Model-Ausgaben, die geschleift werden müssen, die _partials.

Zend_Layout ist nur für das Grund-Gerüst gedacht. Es ist quasi die Obermenge von Zend_View. Sprich Zend_View wird in das Layout eingebettet. Da die View zur entsprechenden Action des beliebigen Controllers gehört, bist du was das angeht, relativ flexibel. Ich mach das immer so:

Code:
Zend_Layout                Zend_View                   Zend_View_Helper
    |--------------> index/index.phtml
    |--------------> news/index.phtml
    |                             |-----------------> partialNews.phtml
    |  usw....

Nachtrag:

Natürlich meine ich im Speziellen den PartialLoop, bei dem du ein iterierbares Objekt übergibst und er sich um die Darstellung kümmert.
 
Zuletzt bearbeitet:
Sehr gut.
Eines noch dann bin ich hiermit komplett.

Ich wollte ein Zend_View erstellen:
PHP:
class Die_SeiteController extends Zend_Controller_Action
{
	public function init()
	{
	}
	
	public function indexAction()
	{
		$this->view->content = $this->view->render('die_site/index.phtml');
	}
}

Edit: Neue frage. Geht es dynamischer ohne das Verzeichnis anzugeben? Also nur 'index.html' ? Oder sogar weniger?
 
Zuletzt bearbeitet:
Zend_View kennt die Methode addScriptPath() mit der du ähnlich wie beim PHP Include Path einen Pfad hinzufügen kannst, der dann durchsucht wird.
 
Du könntest aber auch die View als Plugin machen, somit machst Du Änderungen nur einmal.

So sieht mein View-Plugin aus:
PHP:
class Dart_Controller_Plugin_ViewSetup extends Zend_Controller_Plugin_Abstract
	{
		/**
		 * @var Zend_View
		 */
		
		protected $_view;
		
		public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
		{	
					
			$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
			$viewRenderer->init();			
				$view = $viewRenderer->view;			
			$this->_view = $view;	

			$view->setEscape('stripslashes');
			$view->originalModule = $request->getModuleName();
			$view->originalController = $request->getControllerName();
			$view->originalaction = $request->getActionName();			
			$view->doctype('XHTML1_TRANSITIONAL');			
			$prefix = 'Dart_View_Helper';
			$dir = dirname(__FILE__) . '/../../View/Helper';
			$view->addHelperPath($dir, $prefix);
			$view->headMeta()->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8')
			                 ->appendHttpEquiv('Cache-Control', 'no-cache')
			                 ->appendHttpEquiv('Cache-Control', 'no-store')
			                 ->appendHttpEquiv('Cache-Control', 'max-age=0')
			                 ->appendHttpEquiv('Cache-Control', 'must-revalidate')
			                 ->appendHttpEquiv('expires', '0')
			                 ->appendHttpEquiv('pragma', 'no-cache');
			                 
			$view->headLink()->appendStylesheet($view->baseUrl(). '/css/ddlevelsmenu-base.css');
			$view->headLink()->appendStylesheet($view->baseUrl(). '/css/ddlevelsmenu-sidebar.css');
			$view->headLink()->appendStylesheet($view->baseUrl().'/css/page.css');
			$view->headTitle();
			$view->headScript()->appendScript('function setBaseUrl(){
			var baseUrl = "'.$view->baseUrl().'";
			return baseUrl;
			}
			', 'text/javascript',array());
			$view->headScript()->appendFile($view->baseUrl() . '/js/ddlevelsmenu.js');
			$view->headScript()->appendScript("ddlevelsmenu.setup('ddsidemenubar', 'sidebar')");

			
		}
		
		public function postDispatch(Zend_Controller_Request_Abstract $request)
		{
			if(!$request->isDispatched()){
				return;
			}
			
			$view = $this->_view;
			
			if(count($view->headTitle()->getValue()) == 0){
				$view->headTitle($view->title);
			}
			
			$view->headTitle()->setSeparator(' - ');
			
			$allgemein = new Allgemein();			
			$rob = $allgemein->find(1)->current();
			$title = $rob->siteTitle();
			
			$view->headTitle($title);
		}
	}

Dieses musst Du noch im FrontController registrieren:

PHP:
$frontController = Zend_Controller_Front::getInstance();
			$frontController->throwExceptions(true);
			$frontController->setControllerDirectory(ROOT_DIR . '/application/controllers');
			$frontController->registerPlugin(new Dart_Controller_Plugin_ViewSetup(),97);
			
			Zend_Layout::startMvc(array('layoutPath' => ROOT_DIR . '/application/views/layouts'));

und so kannst Du in jedem Controller und Action die View-Vars füllen:

PHP:
public function myAction(){
			/* do something */
           $this->view = $something;
			
		}

und im Template dann mit $this->something
 
Zuletzt bearbeitet:
Ich verstehe noch nicht ganz, warum man im Controller ein View rendern will. Das macht Zend_Layout doch ganz von alleine. Du brauchst lediglich ein view-Script erstellen (da du sonst ohnehin eine Exception bekommst). Dieses View-Script kann dann assigned Variablen verwenden.

Ich mach das grundsätzlich so:

zf.bat/sh aufrufen, um mein App-Skeleton zu erstellen. Dann meine Controller mit zf erstellen und anschließend Actions im Controller erzeugen. Das alles geht ganz einfach mit zf. Du brauchst da keine einzige Zeile Code anfassen.

Dann wird das application.ini erweitert (Db-Ressource einhängen, Layout-Pfad deklarieren, etc).

Dann Boostrap.php um eine Methode _initLayout() erweitern, in der startMVC() gerufen wird und der Doctype festgelegt. Dann eine Methode _initTranslate() anlegen, in der I18N initialisiert und registriert wird.

Dann eine Methode _initDB() anlegen, in der ein Objekt in Zend_Db::factory() mittels der Resource Db erzeugt wird. Dieses Objekt wird dann auch gleich als Default-Adapter an Zend_Db_Table registriert.

Anschließend kommt das Basis-Layout in application/layouts/main.phtml definiert, was z.B. so aussehen kann:

PHP:
<?php
$this->headMeta()->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8');
$this->headMeta()->appendName('keywords', Bootstrap::getConfigInstance()->application->keywords);

$this->headTitle()->prepend(Bootstrap::getConfigInstance()->application->name);
$this->headTitle()->setSeparator(' - ');

echo $this->doctype('XHTML1_TRANSITIONAL');
?>
<html>
<head>
<?php  echo $this->headMeta(); ?>

<?php  echo $this->headLink()->appendStylesheet('/_files/css/styles.css'); ?>
<?php  echo $this->headLink()->appendStylesheet('/_files/js/dijit/themes/tundra/tundra.css'); ?>

<?php  echo $this->headTitle(); ?>
</head>
<body>

<div id="page">

<div id="header">
<center><h1><?php echo $this->pageName();?></h1></center>
</div>

<div id="main">

<!--
<div id="navi">
<ul>
  <li><a href="#">a</a></li>
  <li><a href="#">b</a></li>
  <li><a href="#">c</a></li>
  <li><a href="#">d</a></li>
</ul>
</div>
-->
<div id="extra">
<?php
if(!Bootstrap::getSess()->user)
{
  $this->formBox('login');
}
else
{
    $this->contentBox('logout');
  $this->contentBox('actions');
    $this->mailBox();
}
?>
</div>

<?php
echo $this->layout()->content;
?>

</div>

<div id="footer">
<?php echo $this->pageFooter(); ?>
</div>

</div>

</body>
</html>

Bis hier hin habe ich ca. 10 Minuten investiert. Die Actions können bereits aufgerufen werden, es werden die Standard-View-Scripts angezeigt.

Nun kann ich die Business-Logik in die Controller-Actions implementieren. Dafür werden natürlich Models benötigt. Diese Models können durchaus erweitertes CRUD implementieren, oder ich nehme einfach die Basis-Funktionen.

Das aufwendigste kommt dann beim designen der View-Scripts. Diese View-Scripts können durchaus auch mal Helper in Form von _partialLoop() verwenden, um z.B. alle Datensätze eines Blogs innerhalb eines bestimmten Zeitraums anzuzeigen.

Bis hier hin habe lediglich meine Controller customized, eigene Models angelegt und View-Scripts definiert.

Ich sehe aber langsam, was dein Problem ist: Du hast sicherlich das Tutorial von Ralf Eggert gelesen. Dieses Tutorial ist leider für das aktuelle ZF überhaupt nicht mehr geeignet. Dort werden viele mittlerweile obsolete Schritte erklärt, wie man das eine oder andere lösen kann.

Eigentlich ist es an der Zeit, ein neues Tut zu schreiben....

Edit:

Vor einiger Zeit hatte ich das allerdings noch so gemacht:

Bootstrap.php:
PHP:
  /**
   * View instance
   * @var Zend_View
   */
  private static $_view = null;


  /**
   * Register a customized view instance
   *
   * @return void
   */
  private static function registerView()
  {
    // get ViewRenderer
    $viewRenderer= Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

    self::$_view = new Zend_View();

    self::$_view->addHelperPath(APPLICATION_DIR . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . 'My/View/Helper', 'My_View_Helper');
    self::$_view->setEncoding('UTF-8');

    // set new View
    $viewRenderer->setView(self::$_view);
  }

  /**
   * Setup the layout
   *
   * @return void
   */
  private static function setupLayout()
  {
    $layout = Zend_Layout::startMvc(array(
			'layoutPath' => APPLICATION_DIR . DIRECTORY_SEPARATOR . 'layouts',
			'layout' => 'main'
			));

			$layout->setView(self::$_view);
  }

  /**
   * Initialization
   * @return void
   */
  public static function initialize()
  {
    Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);
    self::registerView();
    self::setupLayout();
  }
 
Zuletzt bearbeitet:
Zurück