PHP Sammelthread: Zend Framework und alles was dazugehört

Hey Leute ich muss jetzt hier mal fragen. Ihr habt euch ja teilweise schon ein bisschen mehr in Zend_Application reingefuselt und vielleicht wisst Ihr wie man in der globalen Bootstrap eine Routen Config läd und die defaults Route aber erhält.

Also Beispiel ich will folgende Route:
:user.DOMAIN/:modules/:controller/:action/*
:user soll benötigt werden und wenn es nicht existiert muss auf admin/index/index umgeleitet werden.

Das mit der umleitung dachte ich mir mache ich per postDispatch() im Controller, allerdings hänge ich voll an der Routen Config. Das war irgendwie noch nie mein Ding. Hoffe ich habs einigermaßen verständlich erklärt, mein Code in der Bootstrap sieht wie folgt aus:
PHP:
	// ...
protected function _initRouting()
	{
		require_once 'Zend/Loader.php';
		$file = APP_DIRECTORY . '/configs/routes.ini';
		if(!Zend_Loader::isReadable($file)) {
			return;
		}

		$router = Zend_Controller_Front::getInstance()->getRouter(); // gibt standardmäßig einen Rewrite Router zurück
		$router->addConfig(new Zend_Config_Ini($file, APPLICATION_ENV), 'routes');
		return $router;
	}
// ...
 
vielleicht wisst Ihr wie man in der globalen Bootstrap eine Routen Config läd und die defaults Route aber erhält.

Könntest du nicht einfach eine neue Route erstellen und dort dann die Konfig hineinladen? Klingt für mich so simpel, dass ich glaube, dass du das gar nicht wolltest :think:


Ich hab aber eine andere Frage, betreffend Navigation View Helper.

Ich hab ein paar Rootlinks. Diese haben Unterlinks. Standardmäßig werden jetzt die Unterlinks von jedem Rootlink angezeigt. Gibt es eine Möglichkeit (vl. schon vorgefertigte Funktion) mit der man nur die Unterlinks des gerade besuchten Rootlinks anzeigt?
Oder müsste ich das selbst implementieren? Weil dann würde ich einfach einen Link im View machen:ugly:

Edit: setOnlyActiveBranch() sieht gut aus, allerdings fehlt mir noch die Möglichkeit, die Top-Ebene immer zu rendern :think:
 
Zuletzt bearbeitet:
@sebmaster
Ist das nicht das was Du suchst/brauchst
renderMenu($container = null, $options = array()) ist eine standardmäßige render Methode, und stellt einen Container als HTML UL Liste dar.

Wenn $container nicht angegeben wird, wird der Container der im Helfer registriert ist dargestellt.
Ist es nicht so das wenn ich einfach eine neue Route erstelle die Default gelöscht wird? So habe ich es zumindest irgendwie in Erinnerung und das ist das was ich ja nicht möchte.
 
So Leute jetzt müsst Ihr nochmal ran, evtl. weiß ja Ice weiter.
Hier mal meine Config:
Code:
[production]
routes.stableHost.type					= "Zend_Controller_Router_Route_Hostname"
routes.stableHost.route					= ":host." HTTP_HOST
routes.stablesHost.chains[0].type		= "Zend_Controller_Router_Route"
routes.stableHost.chains[0].route		= ":module/:controller/:action/*"
routes.stableHost.reqs.host	= "\w+"


[development : production]

[testing : production]
Und hier mein URL Helper im View:
PHP:
<?php echo $this->url(array('module' => 'admin', 'host' => $stable), 'stableHost', TRUE); ?>"><?php echo $this->escape($stable); ?>
Ich will das der Link von dem Stall wie folgt aussieht "https://{stall}.DOMAIN/admin" und zur Zeit schaut der so aus: "https://crazy+hill+range.stallbuch/". ich weiß absolut nicht was ich falsch mache und habe schon alles drei mal durchgelesen und probiert, aber nix will so wie ich es meine.
 
So Leute jetzt müsst Ihr nochmal ran, evtl. weiß ja Ice weiter.
nein tut mir leid, ich hatte mit noch keinem App die Zeit auf 1.8 zu migrieren.



Aber ich habe mal einen Leckerbissen für euch ;)

Ich habe mich mal drangesetzt und aus dem Wiki alle Seiten zum Zf 2.0 rausgesucht:

Das AutoEscaping in Zend_View und das ExceptionNaming wären sehr schöne Dinge, wenn sie umgesetzt werden würden.
 
Hi Leute,

mal wieder hier was schreiben, was haltet Ihr denn von so einem Model Autoloading per "Parent_Project_Controller"?

Seht Ihr irgendwelche Nachteile? Ich habe das ganze jetzt auch mal bei mir implementiert, allerdings mit dem Zend_Loader::isReadable(), funktioniert zwar noch nicht, also ich bekomme keine Instance des Models zurück aber ich wollte einfach mal ne grundsätzliche Meinung von euch dazu hören.
 
Hallo Leute,

wo seits Ihr denn alle? Habe ich irgendwas verpasst? Mit meiner "Model laden Geschichte" bin ich fertig, ich habe es mit einer abwärtskompatiblem "Late Static Binding" Method gemacht, welche mir immer ein Singleton zurückgibt. Wenns jemanden interessiert, hier der Code und Kommentare oder Verbesserungen sind erwünscht:
Project_Model:
PHP:
<?php
/**
 * {PROJECT} Application
 *
 * This file is part of {PROJECT}
 * Copyright (c) 2009 by RedRaft
 * All rights reserved
 *
 * @category		RedRaft
 * @package			Library
 * @copyright		RedRaft (https://www.redraft.de)
 * @author			Daniel Schumann
 * @license			{LICENSE}
 * @version			$Id: $
 */

/**
 * Project_Model
 * 
 * this is the abstract Project_Model class
 * for the Library of my ZF Application.
 * It stores some usefull methods for other Module Models.
 *
 * @category		RedRaft
 * @package			Library
 * @subpackage		Model
 * @copyright		RedRaft (https://www.redraft.de)
 * @license			{LICENSE}
 */
abstract class Project_Model
{
	/**
	 * Instance array for the called Model
	 * on request.
	 * @var array
	 */
	protected static $_modelInstances = array();

	/**
	 * DB Connection Instance
	 * @var Zend_Db_Adapter_Pdo_Abstract
	 */
	protected $_objDb = NULL;

	/**
	 * DbTables Klass Array
	 * @var array
	 */
	protected $_tables = array();

	/**
	 * getMax gets the max value from the spezified Table
	 * 
	 * @param string $_column	the column name
	 * @param string $_table	the Table where the column stored
	 * @return integer
	 */
	public function getMax($_column, $_table)
	{
		$sql = 'SELECT MAX(?) FROM ' . $this->useTable($_table)->name() . ' GROUP BY ?';
		return $this->objDb->fetchOne($sql, array($_column, $_column));
	}

	/**
	 * table returns the infos of an given DbTable Class.
	 * The $_key parameter is optionaly, possible params are:
	 * NULL	=> for all infos
	 * or the params separatly from Manual @see https://framework.zend.com/manual/de/zend.db.table.html#zend.db.table.info
	 * 
	 * @param string $_name
	 * @param NULL|string $_key
	 * @return array|mixed
	 */
	public function table($_name, $_key = 'name')
	{
		if(!array_key_exists($_name, $this->_tables)) {
			$class = ucfirst(Zend_Controller_Front::getInstance()->getRequest()->getModuleName()) . '_Model_DbTable_' . ucfirst($_name);
			$this->_tables[$_name] = new $class;
		}

		// returned all datas
		if($_key === NULL) {
			return $this->_tables[$_name]->info();
		}

		if(in_array($_key, array('name','cols','primary','metadata','rowClass','rowsetClass','referenceMap','dependentTables','schema'))) {
			return $this->_tables[$_name]->info($_key);
		}
		return NULL;
	}

	/**
	 * Constructor
	 * fetch the db connection Resource
	 * 
	 * @return unknown_type
	 */
	protected function __construct()
	{
		if($this->objDb === NULL) {
			$this->objDb = Zend_Controller_Front::getInstance()->getParam('Zend_Db');
		}
	}

	/**
	 * Singleton
	 * return the instance of an called Model.
	 * for examble Admin_Model_Stable::getInstance() or so on.
	 * 
	 * @return object "Module"_Model_"Modelname"
	 */
	final public static function getInstance()
	{
		// PHP Version Switch
		$class = version_compare('5.3', PHP_VERSION, '<=') ?  get_called_class() : self::get_called_class();
		if(!array_key_exists($class, self::$_modelInstances)) {
			self::$_modelInstances[$class] = new $class;
		}
		return self::$_modelInstances[$class];
	}

	/**
	 * prevent too clone the object
	 * because Singleton.
	 * 
	 * @return void
	 */
	final private function __clone() {}

	/**
	 * Imitat the laste static Binding on PHP Version < 5.3
	 * 
	 * source from: @link https://www.php.net/manual/pl/function.get-called-class.php#89478
	 * @return string
	 */
	static private function get_called_class()
	{
		$bt = debug_backtrace();
		$lines = file($bt[1]['file']);
		preg_match('/([a-zA-Z0-9\_]+)::'.$bt[1]['function'].'/',
			$lines[$bt[1]['line']-1],
			$matches);

		return $matches[1];
	}
}
z.B. Admin_Model_Bla:
PHP:
<?php
/**
 * {PROJECT} Application
 *
 * This file is part of {PROJECT}
 * Copyright (c) 2009 by RedRaft
 * All rights reserved
 *
 * @category		RedRaft
 * @package			Library
 * @copyright		RedRaft (https://www.redraft.de)
 * @author			Daniel Schumann
 * @license			{LICENSE}
 * @version			$Id: $
 */

/**
 * Admin_Model_Stable
 *
 * @category		RedRaft
 * @package			Admin Modul
 * @subpackage		Model
 * @copyright		RedRaft (https://www.redraft.de)
 * @uses			Project_Model
 * @license			{LICENSE}
 */
class Admin_Model_Stable extends Project_Model
{
	/**
	 * getStablesList fetch all stables hwo saves in DB.
	 * returned Format ist 
	 * array(
	 * 	ID	=>	NAME,
	 * 	ID2	=>	NAME2
	 * 	...
	 * )
	 * The Id is the primary in stables Table and unique!
	 * 
	 * @return array
	 */
	public function getStablesList()
	{
		$sql = 'SELECT `id`,
						REPLACE(`name`, " ", "_") AS `name` 
					FROM ' . $this->table('Stable');
		return $this->objDb->fetchPairs($sql);
	}
}
aufruf über:
PHP:
$this->view->stables = Admin_Model_Stable::getInstance()->getStablesList();

Bitte nicht an meinen Kommentaren bzw. meinem Englisch stören, "that`s is not the best" :mrgreen:

So dann hoffe ich mal das hier wieder Leben in die Bude kommt und ich ein paar interessante Denkanstöße bekomme.
 
Zuletzt bearbeitet:
Ein Denkanstoß:
Wenn du mal mit UnitTests deinen Code testen willst, bekommst du ein Problem, weil du deine Models nicht mocken kannst, auf Grund deiner Singleton-Initialisierung.
Mach doch die Erstellung des Model-Objektes als Methode des Controllers, dann kannst du das ohne Probleme mocken.

Nebenbei:
Das Zf 1.9 Preview Release ist da, und Matthew hat mal ein paar Worte darüber verloren.
 
Ich hab mal wieder ein Problem :biggrin: Und hab grad viel zu lange rumprobiert, bis ich auf die Idee kam mal hier zu fragen :ugly:

Ich möchte den ViewScript Path ändern. Ich habe meine Templates in /application/modules/default/views/scripts/index und einen IndexController. Jetzt soll aber ein weiterer Controller FooController dazu kommen. Dieser soll automatisch das passende Template in dem Templateordner vom IndexController aufrufen. Also wenn ich z.B. foo/bar aufrufe, soll der auch index/bar.phtml öffnen statt foo/bar.phtml.

Wie kann ich das ändern?
Ich habe schon versucht, dass über Zend_Controller_Action_Helper_ViewRenderer->setViewScriptPathSpec zu ändern, aber das akzeptiert er so nicht. Es kommt auch kein Fehler, es wird das Layout ausgegeben, aber kein Content :-?
 
Also wenn ich die Doku richtig verstanden habe sollte es wie folgt gehen:
PHP:
$this->_helper->ViewRenderer->setViewBasePathSpec(':moduleDir/views/scripts/index')->setViewScriptPathSpec(':action.:suffix');
*ungetestet*
 
also der Einsatzzweck kommt mir schon komisch vor.

Warum leitest du dann nicht einfach mit _forward auf den Controller weiter? Oder vllt sind ja Partials die Lösung?
 
Also wenn ich die Doku richtig verstanden habe sollte es wie folgt gehen:
PHP:
$this->_helper->ViewRenderer->setViewBasePathSpec(':moduleDir/views/scripts/index')->setViewScriptPathSpec(':action.:suffix');
*ungetestet*

Thx, so klappts. Hatte das vorher alles in setViewBasePathSpec aufgerufen, wusste gar nciht das es die zweite Methode gibt :D

also der Einsatzzweck kommt mir schon komisch vor.
Ich habe ein paar Seiten, die von der Ausgabe haargenau das selbe machen, von der Technik dahinter aber fast vollkommen unterschiedlich sind.
Oder gibt es da bessere Ansätze das ganze anzugehen mti dem ZF?

Und da es ganze Seiten sind, sind Partials nicht so ganz das was ich brauche.
 
Ich habe ein paar Seiten, die von der Ausgabe haargenau das selbe machen, von der Technik dahinter aber fast vollkommen unterschiedlich sind.
Oder gibt es da bessere Ansätze das ganze anzugehen mti dem ZF?

Und da es ganze Seiten sind, sind Partials nicht so ganz das was ich brauche.
wenn sie haargenau die selbe Ausgabe haben, sind Partials eine sehr gute Lösung ;)
Du definierst deinen bisherigen View des IndexControllers als View-Partial und überall wo du auch die Ausgabe brauchst nutzt du dann den Partial ;)
 
Nagut ok ;) Ich dachte bis jetzt immer, die sind für kleine Teile die oft wiederholt werden. Dann werd ichs glaub ich so machen, ist dann auch übersichtlicher.
 
Hey Leute, wenn Ihr einmal da seit, wie funzt des mit Zend Application den Resource Autoloader zu Conf´n?

Ich will in meiner App Strucktur auch ein models Verzeichnis direkt unterhalb von application neben modules.

Ich habe es wie folgt versucht
Code:
autoloaderNamespaces[]									= "Project_"
autoloaderNamespaces[]									= "Model_"
autoloader.resourceTypes.model.namespace= "Model"
autoloader.resourceTypes.model.path= APP_DIRECTORY "/models"
auch ohne das autoloader davor, jedoch alles ohne Erfolg. Ich google schon seit fast zwei Tagen nach dem ganzen Zeug und finde einfach nix. Habt Ihr vielleicht eine Idee oder nen Ansatz für mich? Und eins vorweg, ich möchte nicht einfach nur das Model Verzeichnis in den IncludePath hauen weil ich es mappen will wie die Modules z.B. Model => models usw.
 
Dann will ich hier auch mal eine Frage los werden...

Ich blick noch nicht so ganz durch das Beziehungssystem bei Zend_Db_Table durch.
Folgendes möchte ich quasi erreichen:
Code:
SELECT table.foo, table2.bar FROM table LEFT JOIN table2 ON(table2.b_id = table.b_id) WHERE table1.s = 1 AND table2.u_id = 1 ORDER BY table2.bar

Für table sowie table2 habe ich dann jeweils eine Klasse welche alles von Zend_Db_Table_Abstract erben.
Nun muss ich doch in meiner "Hauptklasse", table, das Attribut $_referenceMap definieren. Das schaut so aus:

PHP:
<?php
    protected $_referenceMap = array(
        'Table2' => array(
            'columns'       => 'b_id',
            'refTableClass' => 'Table2',
            'refColumns'    => 'b_id'
        )
    );
?>

Ich hoffe, dass es so weit richtig ist..
Nun weiß ich allerdings nicht wie ich das ganze auslesen soll.

PHP:
<?php
$table = new Table();
$tableRows   = $table->fetchAll('s = 1');
?>

So würde es bei mir ohne die weitere Tabelle aussehen.
Die Methoden findParentRow() / findDependentRow() sowie findManyToManyRowset() sind ja nicht für das Model sondern für das Rowset bzw. die einzelnen Rows.

Wird durch die referenceMap automatisch schon eine Verbindung hergestellt und ich muss die dann später im Rowset erst durch die zweite Tabelle einschränken und sortieren irgendwie? Fände ich komisch, da dass dann doch auf PHP Ebene passiert?

EDIT: Um so mehr ich hier herumteste, um so mehr bekomme ich das Gefühl, dass der Weg über eine referenceMap ganz andere Probleme löst und nicht für mein Problem ist... !?
 
Zuletzt bearbeitet:
Kann dir leider nicht helfen chrissel, aber ich hab auch ne Frage :biggrin:

Wie kann ich die komplette URL erhalten? Oder alles nach einem bestimmten Teil?

Ich habe eine Route foo/* und das was nach foo/ ist, würde mich interessieren. Da kann alels Mögliche drin stehen, die Parameter Anazhl ist auch nicht fest. Deswegen würde ich das ganze gerne als einen String haben. Wie bekomme ich das hin?