PHP Sammelthread: Zend Framework und alles was dazugehört

Hi Leute, muss euch nun mal was fragen, da ich noch recht am Anfang bin mit meinem Teil, möchte ich lieber von vornherein einiges bedenken. So z.B. sogenannte Content-Boxen, ich nenne sie jetzt mal so, keine Ahnung wie die genau heißen, als Beispiel nehme ich jetzt mal das FWX.

Z.B. die Startseite nach dem Login, da sag ich mal sehe ich jetzt Werbung, Shoutbox und News. Wie könnte man das mit dem ZF umsetzen? Fällt euch da vielleicht spontan etwas dazu ein, da ja alles in Content gespeichert wird.

Mein Ansatz ist gerade einen View_Helper fürs Layout der auf dem Placeholder Helper aufbaut. Um z.B. einen content-Array zu füllen:
PHP:
$content = array(
  array('title' => '1...', 'content' => 'werbung'),
  array('title' => '2...', 'content' => 'shoutbox'),
  array('title' => '3...', 'content' => 'news')
);
PHP:
//Helper
foreach($array AS $_box) {
  $this->setTitle($_box['title']);
  //...
}

// destructor
public function __destruct()
{
  // assign too Placeholder
}

Nur wie könnte man das Array bequem füllen, ich meine das ZF rendert automatisch die Views, sollte man:
1. in der Action ein Array übergeben mit weiteren Actions die gerendert werden sollen.
2. Sollte man lieber gleich in den jeweiligen Views den Action View Helper nutzen.

Irgendwie gefallen mir beide Versionen nicht so recht, vielleicht hab Ihr bessere Ideen.
 
Ja partials wäre auch eine Möglichkeit, würdest Du es dann also direkt in den View mit Partials machen? Ohne eigenen Helper, oder ne Mischung aus allem.
 
Willkommen beim Zend Framework ;)

Nimm die neueste Versionen. Die anderen Versionen sind Release, die Sicherheitslücken beheben für Personen, die noch alte Releases einsetzen und nicht auf die neuen Umsteigen können/wollen.
 
begrüße!

ich bekomme das mit dem autoload einfach nicht zum laufen..

ich habe ein modul namens "admin".. in der application.ini bestimme ich das modulDirectory mit folgender zeile:
Code:
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

das modul selbst funktioniert an sich auch wunderbar.. über die url admin/acl/roles komme ich wie gewünscht in das modul "admin" in den controller "Acl" und die action "roles"..

wenn ich jetzt aber eine datei aus diesem modul laden will (also zb ein formular), dann bekomme ich die fehlermeldung:
Fatal error: Class 'Admin_Form_Roles' not found in /var/www/QMS2/application/modules/admin/controllers/AclController.php on line 28

die klasse befindet sich in application/modules/admin/forms/Roles.php

in der bootstrap habe ich für den modul autoloader folgende init methode:
PHP:
    protected function _initAutoload()
    {
        $moduleloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Default',
            'basePath'  => implode(DIRECTORY_SEPARATOR, array(
                                dirname(__FILE__),
                                'module',
                                'default'
                            ))
        ));
        return $moduleloader;
    }

das letzte mal als ich probleme mit dem autloading hatte hat strolch00 vorgeschlagen, dass ich ne eigene bootstrap für das modul mache und dort den modul autoloader anpasse.. habe ich versucht, allerdings wird die bootstrap im modul nicht ausgeführt (habe ich mit ein paar debugging ausgaben überprüft) die bootstrap liegt im root verzeichnis des moduls..

ich weiß wirklich nicht weiter.. mit require_once() funktioniert es natürlich.. aber das kann nicht der weisheit letzter schluss sein ;)

bin für jegliche ideen, links oder schlagworte mehr als dankbar ;)
 
Hi Wizzler, sorry das war evtl. mein Fehler, in Deiner application.ini hast sicher auch folgendes stehen:
Code:
resources.modules =
Also nutzt Du damit auch den Module_Resource Loader * oder wie sich das Ding auch immer schimpft, weiß Ice sicher * also legst Du folgende Module Bootstrap an
PHP:
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{
	/**
	 * Start Autoloader
	 * 
	 * @access protected
	 * @return Zend_Application_Module_Autoloader
	 */
	protected function _initAutoload()
	{
		$autoloader = new Zend_Application_Module_Autoloader(array(
			'namespace' => 'Admin',
			'basePath'  => dirname(__FILE__),
		));

		return $autoloader;
    }
}
und initiierst damit die neue Admin Pfad Ressource so das der im Admin Modul nach Forms und dergleichen sucht.

So eine Bootstrap musst in jedem Modul liegen wo du Forms usw. nutzt !AUßER! im default Modul(für default gilt die "globale", mir ist leider noch keine Möglichkeit eingefallen wie man das in der globalen Bootstrap für alle Module realisieren könnte.

*edit
...eigene bootstrap für das modul mache und dort den modul autoloader anpasse.. habe ich versucht, allerdings wird die bootstrap im modul nicht ausgeführt (habe ich mit ein paar debugging ausgaben überprüft) die bootstrap liegt im root verzeichnis des moduls..
Das passiert, soweit ich informiert bin, mit obigen Configeintrag.

*edit2
Hab auch grad noch ein bisschen mit dem Autoloader rumgespielt und bin auf einen, meiner Meinung nach, einfachen Weg gestoßen um einen Resource Pfad für Zend_Loader::isRedable() zu erhalten.

PHP:
$path = Zend_Controller_Front::getInstance()->getParam('bootstrap')
	->Autoloader->getClassPath($className)
@Wizzler in deinem Fall müsstest Du auf Autoload zugreifen, weil mir das net gefallen hat habe ich meine Bootstrap Funktion _initAutoload() in _initAutoloader umbenannt, evtl. ist aber der Zugriffsname ModuleLoader noch für dein einen oder anderen intuitiver zu handhaben.
*zusatz:
Find ich grad (zu so später Stunde) saugeil, weil das mir einiges Code mit Filtern und str_replace() spart, um einen Klassennamen zum Klassenpfad aufzulösen.
 
Zuletzt bearbeitet:
hi strolch00!
danke für die antwort!

die zeile
Code:
resources.modules =

hat in meiner konfiguration gefehlt.. jetzt läuft es.. jeweils mit einer modul bootstrap.. um das ganze in einem rutsch zu machen und nicht jeweils ne eigene bootstrap erstellen zu müssen fehlt mir grade der nerv :ugly:
danke auf jeden fall!

dann habe ich gleich noch nen paar fragen, wie ihr die dinge so bei euch aufbaut ;)

standardmäßig sollen die meisten formulare ja eine insert und eine update funktion bieten.. wie löst ihr das? im prinzip ist es ja in beiden fällen das gleiche.. bei der update funktion gibt es halt noch ne datenbankabfrage und ein $form->populate($data) und beim schreiben der datensätze werden andere methoden des models aufgerufen..

deswegen habe ich die insert und die update funktion in eine einzige action gepackt.. hat den vorteil, dass der code nicht reproduziert werden muss.. außerdem muss man nicht zwei verschiedene view scripts erstellen..

ich habe allerdings das validieren des formulars auch noch in diese action gepackt.. und irgendwie ist es jetzt doch einiges an geschäftslogik im controller.. deswegen würde mich interessieren, wie ihr das löst..

was mich ebenfalls interessieren würde.. wie übergebt ihr die daten für den insert bzw das update an das model? im prinzip kommen die daten ja schon in der richtigen form aus dem formular.. deswegen liegt die idee nahe, einfach die daten aus dem formular zu übergeben (escapen im model inklusive, versteht sich ;) )
aber da sind halt auch meistens daten dabei, die nicht in der datenbank stehen (zb der wert des submit buttons).. entfernt ihr die "überflüssigen" einträge bevor ihr sie an das model übergebt? überprüft ihr im model, welche der keys im übergebenen array relevant sind? oder erstellt ihr im controller händisch einen array mit den relevanten daten?

fragen über fragen.. und umso länger ich mit mit dem framework arbeite, umso mehr werden es (so kommt es mir zumindest vor :D )

edit: sorry für die romane die ich hier immer schreibe ;)
 
Wegen der Model Speicherung, gibt dem Submit Button einfach ein
PHP:
array(..., 'ignore' => TRUE, ...)
mit das steht der Wert nicht im Daten array. Also von mir mal ein Guestbook Form:
PHP:
<?php
class Default_Form_Guestbook extends Zend_Form
{
	public function init()
	{
		$this->setMethod(Zend_Form::METHOD_POST);
		$this->setAction('/guestbook/sign');

		$this->addElement('hidden', 'created', array(
            'required'		=> true,
			'value'			=> date('Y-m-d H:i:s')
		));

		$this->addElement('text', 'email', array(
			'label'      => 'Your email address:',
			'required'   => false,
			'filters'    => array('StringTrim'),
			'validators' => array(
				'EmailAddress',
			)
		));

		$this->addElement('text', 'website', array(
			'label'      => 'Your Website address:',
			'required'   => false,
			'filters'    => array('StringTrim'),
			'validators' => array(
				'Hostname',
			),
			'description' 	=> 'ohne https://'
		));

		$this->addElement('textarea', 'comment', array(
			'label'		 => 'Please Comment:',
			'required'	 => true,
			'rows'		 => 5,
			'cols'		 => 30,
			'validators' => array(
				array('validator' => 'StringLength', 'options' => array(0,220))
			),
			'description' 	=> 'bis zu 220 Zeichen'
		));

		// Add a captcha
        $this->addElement('captcha', 'captcha', array(
            'label'      => 'Please enter the 5 letters displayed below:',
            'required'   => true,
            'captcha'    => array(
                'captcha' => 'Figlet', 
                'wordLen' => 5, 
                'timeout' => 300
            )
        ));

        // Add the submit button
        $this->addElement('submit', 'submit', array(
            'ignore'   => true,
            'label'    => 'Sign Guestbook',
        ));

        // And finally add some CSRF protection
        $this->addElement('hash', 'csrf', array(
            'ignore' => true,
        ));
	}
}

Und wegen der Methoden und Validierung, muss ich gestehen habe ich mir selber bisher keine Gedanken gemacht. Bissher hatte ich immer entweder mit einer abstracten Klasse gearbeitet oder zur Validierung einen Action-Helper verwendet der mir die Felder gleich als Error markiert zur CSS steuerung. Das ganze hab ich aber auch als zu aufwendig empfunden und bin gerade selber dabei nochmal meine gesammelten Werke neu zu konzeptionieren. Gerade habe ich leider erst meine Mapper usw. fertig. Zur Form-Sache komme ich jetzt dann erst. Das Guestbook Form ist auch nur aus dem Quickstart zu test der Mapper gewesen.

Btw. fals es euch interessiert poste ich mal meine Lösung, hab da ein bisschen mit "late static binding" gespielt und komme nu komplett ohne Factory aus. Einfach nur Model instanzieren und fertig.

Sorry wegen Rechtschreibfehlern, bin etwas im Stress :mrgreen:

edit 2:
Hab auch vorhin bei Matthew gesehen das er die Form komplett mit Validierung in Model gesteckt hat, hab es nur grob überflogen, aber eine weiter Möglichkeit wäre auch das.
*Hoffe es ist der richtige Link.
 
Aktuell gefunden, scheint recht interessant zu sein um einen das Leben zu erleichtern. Ich werde das mal grob testen, es ist ein Model, DbTable und Mapper generator für das ZF basierend auf der vorhanden DB. Hoffe ich hab das so richtig interpretiert.
 
Das neue ZF 1.10 wurde fertig gepackt ;)
Die Neuerungen sind doch beträchtlich.

Besonders interessant finde ich:
  • Static Backend Cache
  • Zend_Markup
  • Zend_OAuth
  • Zend_Serializer (kommt gerade richtig :biggrin:)
  • Zend_Service_LiveDocx
 
begrüße!

ich hätte mal gerne wieder einen rat! ;) und zwar bin ich momentan dabei meine controller schlanker zu gestalten und habe mich deswegen dazu entschieden die formulare komplett mit ins model zu übernehmen wie in dem von strolch00 verlinkten post.. erscheint mir irgendwie logisch..

mich würde jetzt interessieren, wie ihr die verschiedenen status in euren formularen handhabt? in der regel gibt es ja zumindest 2 verschiedene status: einen "edit" status und einen "add" status, wobei typischerweise action tag angepasst werden muss und man wahrscheinlich noch die überschrift des formulars ändern will..

wie löst ihr das problem?

mein erster gedanke war es, die beiden status direkt im formular über variablen zu definieren.. also einen variable "addAction" = "/admin/roles/edit/?" wobei das fragezeichen durch die id ersetzt wird.. und dann eben entsprechend eine add action.. aber die lösung finde ich alles andere als optimal.. deswegen würde mich interessieren wie ihr das löst und hoffe auf kreative ansätze ;) eventuell über ein hidden field? auch nicht so das wahre..

das formular wird bei mir im controller über das model geladen.. also $model->getForm().. es wäre auch möglich an dieser stelle eine id bzw null zu übergeben.. wird eine zahl übergeben stellt das model auf den edit modus, wird null übergeben stellt das model auf den add modus.. wobei dann immer noch das problem mit dem speichern der verschiedenen actions wäre..

bin über jeden tipp dankbar ;)
mfg
whizzler
 
Hey Leute ich brauch mal dringend eure Hilfe, es betrifft Zend_View und Model/Mapper Objecte:

Also folgende Gegebenheiten:
im Controller folgende Zuweisungen
PHP:
		$model = new Model_User;
		$this->view->members = $model->fetchAll();
		$this->view->roles = $model->getRoles();
		$this->view->status = $model->getStatus();
im View folgende Abfragen
PHP:
//...
    by Status:<br />
    <span class="pd_lft_20">
      <select class="changer">
<?php foreach($this->status AS $_k => $_status): ?>
        <option value="<?php echo $this->url(array('module' => 'admin', 'controller' => 'user', 'action' => 'index', 'status' => urldecode($_status)), 'default', TRUE); ?>"><?php echo $this->escape($_status); ?></option>
<?php endforeach; ?>
      </select>
    </span>
//...
foreach($this->members AS $_user): ?>
    <tr<?php echo ((++$x % 2) == 1) ? '' : ' class="th"'; ?>>
      <td><?php echo $this->escape($_user->real_name); ?></td>
      <td class="center"><?php echo $this->escape($_user->nick); ?></td>
      <td class="center"><?php echo $this->escape($_user->status); ?></td>
      <td class="center"><a href="<?php echo $this->url(array('module' => 'admin', 'controller' => 'balance', 'action' => 'points', 'id' => $_user->id), 'default', TRUE); ?>" class="popup"><?php echo $this->escape($_user->points); ?></a></td>
      <td class="center"><a href="<?php echo $this->url(array('module' => 'admin', 'controller' => 'balance', 'action' => 'ammount', 'id' => $_user->id), 'default', TRUE); ?>" class="popup"><?php echo $this->escape($_user->ammount); ?> €</a></td>
      <td>
        <a href="<?php echo $this->url(array('module' => 'admin', 'controller' => 'user', 'action' => 'edit', 'id' => $_user->id), 'default', TRUE); ?>">edit</a> --
        <a href="<?php echo $this->url(array('module' => 'admin', 'controller' => 'user', 'action' => 'block', 'id' => $_user->id), 'default', TRUE); ?>" class="verify" title="Are you shure, too block this User?">sperren</a> --
        <a href="<?php echo $this->url(array('module' => 'admin', 'controller' => 'user', 'action' => 'delete', 'id' => $_user->id), 'default', TRUE); ?>" class="verify" title="Are you shure, too delete this User?">delete</a>
      </td>
    </tr>
<?php endforeach; ?>
zum debuggen habe ich vor der foreach im View noch folgendes
PHP:
Zend_Debug::dump($this->members, 'Members:');
Zend_Debug::dump($this->status, 'Status-Select:');
Die Ausgabe des debuggens sieht wie folgt aus:
Members: array(1) {
[0] => object(Model_User)#69 (11) {
["_id":protected] => int(2)
["_nick":protected] => string(7) "xxxxx"
["_password":protected] => string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
["_status":protected] => string(8) "inactive"
["_role":protected] => string(4) "user"
["_real_name":protected] => string(12) "xxxxx xxxx"
["_email":protected] => string(14) "[email protected]"
["_random_salt":protected] => string(0) ""
["_points":protected] => string(9) "519625.00"
["_ammount":protected] => string(8) "9999.999"
["_mapper":"System_Model_Abstract":private] => NULL
}
}

Status-Select: array(2) {
[0] => string(6) "active"
[1] => string(8) "inactive"
}


So und nun bekomme ich aber durch das innerhalb der foreach vorhandene
PHP:
echo $this->escape($_user->status);
immer die Fehlermeldung:
Warning: htmlspecialchars() expects parameter 1 to be string, array given in G:\xampp\htdocs_paid4Zf\library\Zend\View\Abstract.php on line 848

Ich denke Zend_View versucht durch __call() das Status array in der foreach zu übergeben, weil im Model ein string ist, aber warum. Ich bin echt ratlos und hoffe jemand von euch hat ne Lösung.
 
Ich poste jetzt mal in einem neuen, weil es mit meinem Problem nix zu tun hat.

Ich bin ja gerade dabei mein Model/Mapper System zu erstellen und beim rumspielen hatte ich heute genau das selbe Problem. Bei mir ist die Form noch nicht im Model implementiert, aber es ist trotzdem einfach zu handlen. Bin mir auch noch nicht sicher ob ich es integrieren will, hat vor und Nachteile in meinen Augen.

Aber hier mal kurz ein Umriß meiner Strategie, eine Form muss genau die Felder haben die auch mein Layer hat, es muss zumindest immer das primary Feld dabei sein, als hidden und nicht required. So stelle ich sicher das wenn ich das Form in der new-Aktion nutzt primary gleich NULL ist und in edit-Aktion, steht im primary das value drin.

Und durch die Trennung meiner save() Method nach insert und update, passiert der Rest automatisch.

Wenn Du noch Code brauchst poste ich den noch, aber vielleicht hilft Dir schonmal die Erklärung dazu, ist aber evtl. bissl zu chaotisch erklärt.

*edit
Hier mal ein bisschen Code um das ganze leichter zu verstehen, wieder als Beispiel das Guestbook:
PHP:
	public function indexAction()
	{
		$guestbook = new Model_Guestbook();
		$this->view->entries = $guestbook->fetchAll();
	}

	public function editAction()
	{
		if(($id = $this->_getParam('id')) == NULL) {
			$this->_redirect('/guestbook');
		}

		$model = new Model_Guestbook;
		$form = new Default_Form_Guestbook;
		if($this->getRequest()->isPost()) {
            if($form->isValid($this->getRequest()->getPost())) {
                $model->setProperties($form->getValues())
                	->save();
                // redirect
                $this->_helper->redirector('index');
            }
        }
        $form->populate($model->find($id)->toArray());
        $this->view->form = $form;
	}
 
mich würde jetzt interessieren, wie ihr die verschiedenen status in euren formularen handhabt? in der regel gibt es ja zumindest 2 verschiedene status: einen "edit" status und einen "add" status, wobei typischerweise action tag angepasst werden muss und man wahrscheinlich noch die überschrift des formulars ändern will..
Edit ist klar, das ist das Anpassen eines bereits existierenden Model-Objektes.
Das Hinzufügen könntest du nun einfach implementieren als das Bearbeiten eines leeren Model-Objektes ;)
Beidesmal die gleiche Logik, nur die Speicherung musst du eben je nach Fall anders implementieren.

Ich denke Zend_View versucht durch __call() das Status array in der foreach zu übergeben, weil im Model ein string ist, aber warum. Ich bin echt ratlos und hoffe jemand von euch hat ne Lösung.
Der Status ist protected, also versucht PHP über call daran zu kommen, da es auf Grund der Sichtbarkeit nicht direkt zugreifen darf. Warum da ein Array daraus wird, können wir dir nicht sagen, ohne die call-Methode sehen zu können.
 
Hi Ice,

also ich habe in meinen Model_Abstract dafür diese __get()
PHP:
	/**
	 * Returns an requested Propertie from the used Layer,
	 * only if an valid Getter Method exists.
	 * @param string $_key
	 * @return mixed
	 */
	public function __get($_key)
	{
		$methods = array_filter(
			get_class_methods($this),
			array($this->getMapper(), 'getOnlyModelGetter')
		);

		if(!in_array(($method = 'get' . ucfirst($_key)), $methods)) {
			throw new System_Model_Exception(sprintf('Unknown Property (%s)!', $method));
		}
		return $this->{$method}();
	}
Sollte ja ausreichen um die Variablen zu erhalten. Ich meinet die __get() oder __call() von Zend_View_Abstract, wobei __call() nur Helper called.
 
debuggen, debuggen, debuggen ...

aus der Ferne kann ich so nichts erkennen, musst du mal Schritt für Schritt alles nachvollziehen, was da passiert
 
Hey Leute mal ne doofe Frage, gibt es eine Komponente im ZF mit der man einfach API Abfragen wie EF oder Werbenetzwerk Interfaces abfragen kann. Ich hab im Manual nix gefunden, allerdings habe ich evtl. in den falschen Komponenten gesucht.

Danke