Zum Inhalt springen

Anfängerfragen Extbase

Erstellt am 14. März 2013 · 18 Antworten · letzte Antwort am 2. Mai 2013

Tags: Frage

Philipp88 ·

Hi🙂

Ich bin gerade dabei mir Extbase anzueignen.
Dazu habe ich 4 Fragen:

1. Wie kann ich, wenn ich in meinem Controller per finAll() alle Datensätze hole mit den SQL- Befehlen "WHERE", "GROUP BY", "ORDER BY", "LIMIT" die Ausgabe ändern? Oder muss ich da ein eigenes Statement schreiben?

2. SQL wird ja erst ausgeführt, wenn ich die Daten für den Viewhelper benötige. Was ist aber, wenn ich die Daten erst noch per PHP bearbeiten möchte und die dann erst ausgeben möchte? Früher habe ich per $GLOBALS["TYPO3_DB"]->SQL_fetch_assoc($res) jede Zeile einzeln geholt, Daten abgeändert und in Marker geschrieben. Wie geht sowas?

3. Ich habe folgende Funktion in Repostory:

public function all_name() {
    $res = array(
        "vorname" => "wwe",
        "name" => "wwebhj",
    );
    
    return $res;
}

Wie bekomme ich ein Array - so wie ein SQL- Query - Zeile für Zeile ins Template? Wie muss das Array aufgebaut sein?

4. Wenn ich per Extension Builder eine Extension erstelle, ist ja als Default eingestellt, dass die list- Action als erstes aufgerufen wird. Wie kann man das ändern?

Ich weiß das sind viele Anfängerfragen zum Thema Extbase, hoffe aber trotzdem das jemand die mir antworten kann, würde mich sehr freuen 🙂
Philipp

karf ·
Philipp88 schrieb

1. Wie kann ich, wenn ich in meinem Controller per finAll() alle Datensätze hole mit den SQL- Befehlen "WHERE", "GROUP BY", "ORDER BY", "LIMIT" die Ausgabe ändern? Oder muss ich da ein eigenes Statement schreiben?

Group By gibt es in extbase nicht, wenn du um die nutzung davon nicht rum kommst musst du ein eigenes SQL-Query schreiben. (es gibt aber ein GroupFor Viewhelper, den du eventuell vorher mal ausprobieren solltest)

Für andere Querys musst du das entsprechende Repository erweitern

Dort kannst du mit $this->createQuery() ein neues Query Objekt erstellen und dem Conditions und Sortierung mitgeben. Ich hab leider grad kein Simples Beispiel zur Hand, Schau dir am besten die Klasse \TYPO3\CMS\Extbase\Persistence\Generic\Query an. (wichtige methoden zum beispiel: matching(), execute() und setOrderings())

Für einfache Abfragen wo du nur anhand einer Property filtern musst gibt es die findBy* Methoden.
Also zum Beispiel findByUid() oder findByName() oder wie auch immer deine Properties heißen.

Philipp88 schrieb

2. SQL wird ja erst ausgeführt, wenn ich die Daten für den Viewhelper benötige. Was ist aber, wenn ich die Daten erst noch per PHP bearbeiten möchte und die dann erst ausgeben möchte? Früher habe ich per $GLOBALS["TYPO3_DB"]->SQL_fetch_assoc($res) jede Zeile einzeln geholt, Daten abgeändert und in Marker geschrieben. Wie geht sowas?

Du kannst die Results aus den Repositories auch schon im PHP per foreach Schleife durchgehen. Und deine bearbeiten Dateien dann in ein Array oder ein ObjectStorage stecken und an den View weitergeben.
also zum Beispiel so in der Art.

$array = array();

foreach($this->repository->findAll() as $object)
{
    $object->SetWhatEver(42);
    $array[] = $object;
}

$this->view->assign('list', $array);
Philipp88 schrieb

3. Ich habe folgende Funktion in Repostory:

public function all_name() {
    $res = array(
        "vorname" => "wwe",
        "name" => "wwebhj",
    );
    
    return $res;
}

Wie bekomme ich ein Array - so wie ein SQL- Query - Zeile für Zeile ins Template? Wie muss das Array aufgebaut sein?

Ich verstehe dein Beispiel grad glaube ich nicht ganz 😉
Aber auf ein Array kannst du auf zwei Wege zugreifen.

Wenn du ein Numerisches Array hast, also mit Index von 0 bis n
kannst du mittels des for-ViewHelpers durch iterieren.

und auf keys direkt kannst du mit "." zugreifen, also zum Beispiel "array.key"

Hier ein kurzes Beispiel.

$list = array(array('a' => 1, 'b' => 2),
              array('a' => 3, 'b' => 4),
              array('a' => 5, 'b' => 6),
              array('a' => 7, 'b' => 8-),
             );

$this->view->assign('list', $list);
<f:for earch="{list}" as="value">
<f:comment>{value} ist jetzt immer einer der inneren Arrays aus {list]</f:comment>
    <div>
    {value.a} <!-- 1, 3, 5 oder 7. je nach dem in welcher iteration wir sind -->
    {value.b} <!-- 2, 4, 6, 8 -->
    </div>
    
</f:for>

{list.0.a} würde natürlich ebenfalls 1 ausgeben. Das Funktioniert natürlich nicht mehr
wenn du ein QueryResult (aus dem Repository) oder ein ObjectStorage (aus dem Model) hast.
    
Zu beachten ist eventuell noch, dass du auf die Property eines Models mit {model.property} zugreifst. (dabei wird dann $model->getProperty() ausgeführt)
Philipp88 schrieb

4. Wenn ich per Extension Builder eine Extension erstelle, ist ja als Default eingestellt, dass die list- Action als erstes aufgerufen wird. Wie kann man das ändern?

Dort wo du im Builder dein Plugin definierst, kannst du auch die gültigen Actions angeben.
immer in der Form "Controller => Action1, Action2, Action3" und je eine Zeile pro Controller.

Die erste Action die du hier angibst wird Standardmäßig aufgerufen. (Hier Action1)

Alle Beispiele sind frei runtergetippt, also keine Garantie das sie direkt laufen!

Philipp88 ·

danke für deine ausführliche Antwort 🙂 Leider verstehe ich das bearbeiten der Daten noch nicht ganz🙁 SetWhatEver(42); - Was bedeutet die 42?
Wie bekomme ich die gesamte Anzahl der Datensätze in PHP - ohne sie mit den Viewhelper item auszugeben? Für Berechnung der Seiten in einer Navigation etc.?
Also die Querys mit LIMIT und komplexeren where- Bedingungen kann ich ohne Probleme selbst schreiben oder gibt's da sowas wie findAll() mit Parameter?

karf ·

SetWhatEver(42); ist nur ein Beispiel, weil du ja in PHP noch irgendwas an den Models verändern wolltest bevor du sie dem View übergibst.

Die Anzahl der Datensätze bekommst du mit der Methode QueryResult::count() (QueryResults sind die Objekte die die Repositories zurück geben)

also zum Beispiel, $this->repository->findAll()->count()

Vorsicht, das "count()" funktioniert nicht mehr, wenn du per statement() ein eigenes SQL Query schreibst! Dann wird dir count() immer die Anzahl aller Datensätze zurück geben!

Selber SQL zu schreiben ist in Extbase immer eine schlechte Idee (auch wenn es sich nicht immer vermeiden lässt)

generell gibt es für jede Property deines Models die Methoden FindByProperty() und FindOneByProperty() im Repository. Wobei "Property" der Property name ist, also zum Beispiel findByTitle('test') oder findOneByName('foo'). Ersteres gibt ein QueryResult zurück, das alle Models mit dem Titel "test" beinhalten, das zweite Beispiel gibt dir direkt ein Model mit dem Namen 'foo' zurück. (wenn es mehrere mit dem Namen gibt, dann das erste davon)

Brauchst du mehr als ein Kriterium (oder was anderes wie eine "ist gleich" Beziehung) musst du eine eigene Methode im Repository schreiben.

hier mal ein kleines Beispiel:

	public function findNonPublicByTest(\TYPO3\MyExt\Domain\Model\Test $test) {
		    
		        $query = $this->createQuery();
		        
		        $condition1 = $query->equals('public', false);
		        $condition2 = $query->equals('test', $test);
		        $condition  = $query->logicalAnd($condition1, $condition2);
		        
		        $query->matching($condition);
			     $query->setOrderings(array('titel' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING));
		        
		        return $query->execute();
	}

Hier kriege ich eine Liste aller Datensätze zurück die nicht public sind und in der Property "Test" mit dem übergebenen Objekt übereinstimmen.

Ist etwas umständlich gemacht, aber wenn man sich dran gewöhnt hat funktioniert es eigentlich ganz gut 😉

Wenn es immer noch nicht klar ist, Zeig mir einfach mal wie deine aktuellen Models aussehen, dann tippe ich dir schnell Beispiele anhand deiner eigenen Models zusammen.

tobla ·

Hallo Philipp88

Hinter Extbase steckt ein komplett anderes Konzept als bei der alten pi-Base. Bitte programmiere auf KEINEN Fall in Extbase so, wie du mit pi-Base Extensions geschrieben hast, das kommt nicht gut *schauder*. #angry#

Extbase setzt auf Objektorientierte Programmierung, während pi-Base irgendetwas zwischen strukturierter und undefinierter Programmierung als Konzept voraussetzte. http://de.wikipedia.org/wiki/Objektorientierte_Programmierung

Die Leute von Mittwald haben ein sehr gutes Manual geschrieben, das dich Schritt für Schritt an Extbase heranführt und als Beispiel gleich eine kleine Extension anlegt. https://www.mittwald.de/fileadmin/downloads/pdf/dokus/Extbase_Fluid_Dokumentation.pdf

Das Manual hast du relativ schnell durch. Anschliessend bist du mit den Konzepten vertraut und meines Erachtens lösen sich dann auch alle von dir gestellten Fragen.

Philipp88 ·

Hi ich nochmal 🙂

ich bin richtig am verzweifeln mit Extbase🙁
Also ich arbeite gerade das Tutorial durch was oben verlinkt wurden ist.

Wenn ich wie beschrieben auf Seite 82 den Code schreibe in ProjektController.php

$this->projektRepository = t3lib_div::makeInstance (
"Tx_timetrack_Domain_Repository_ProjektRepository" );

Kommt folgender Fehler:
"Fatal error: Class '\TYPO3\Timetrack\Controller\ProjektController' not found"

Könnt ihr mir helfen?

karf ·
Philipp88 schrieb

Hi ich nochmal 🙂

ich bin richtig am verzweifeln mit Extbase🙁
Also ich arbeite gerade das Tutorial durch was oben verlinkt wurden ist.

Wenn ich wie beschrieben auf Seite 82 den Code schreibe in ProjektController.php

$this->projektRepository = t3lib_div::makeInstance (
"Tx_timetrack_Domain_Repository_ProjektRepository" );

Kommt folgender Fehler:
"Fatal error: Class '\TYPO3\Timetrack\Controller\ProjektController' not found"

Könnt ihr mir helfen?

Irgendwie passt dein Code und deine Fehlermeldung nicht zusammen (einmal Repository und einmal Controller?)

Nutzt du Typo3 4.x oder Typo3 6.x?

und generell würde ich empfehlen Objekte über den Objekt Manager zu erstellen. Also per "$this->objectManager->get($className);"

karf ·

doch die gibt es natürlich. Aber du befindest dich in einem namespace, dann heißt die klasse nicht mehr t3lib_div sondern \t3lib_div

Aber wie gesagt ich würde dir wirklich empfehlen den objectManager zu verwenden. Ansonsten kannst du komische Fehler mit deinen Objekten bekommen.

Also in deinem Fall

$this->projektRepository = $this->objectManager('TYPO3\Timetrack\Domain\Repository\ProjektRepository');

(oder bist du dir sicher das deine Klasse Tx_timetrack_Domain_Repository_ProjektRepository heißt? In Typo3 6 solltest du am besten die namespaces benutzen!)

Noch besser ist es aber natürlich sich die Repositorys direct injecten zu lassen. dazu einfach die @inject Annotation an deine Klasse-Variable schreiben.

also

/**
 * ProjektRepository
 * @var \TYPO3\Timetrack\Domain\Repository\ProjektRepository
 * @inject
 **/
protected $projektRepository;

Danach hast du in $this->projectRepository automatisch deine Repository Klasse drin. (nicht vergessen vorher den Cache zu löschen 😉)

Philipp88 ·

Sorry nochmal 🙁

erstmal Danke, hat geklappt 🙂

jetzt ein anderes Problem:
Wie kann ich im Controller eine neue Funktion anmelden?

The action "cform" (controller "Personen") is not allowed by this plugin

Funktion heißt "cform"

 /**
	 * action cform
	 *
	 * @return void
	 */
	protected function cformAction($person) {
          \t3lib_utility_Debug::debug($person, 'auto');
          
	}

Ich finde die alte Programmierung war verständlicher bzw. einfacher als Extbase oder ändert sich das noch?

karf ·
Philipp88 schrieb

Sorry nochmal 🙁

erstmal Danke, hat geklappt 🙂

jetzt ein anderes Problem:
Wie kann ich im Controller eine neue Funktion anmelden?

The action "cform" (controller "Personen") is not allowed by this plugin

Funktion heißt "cform"

 /**
	 * action cform
	 *
	 * @return void
	 */
	protected function cformAction($person) {
          \t3lib_utility_Debug::debug($person, 'auto');
          
	}

Im Extension Builder, auf der Linken Seite wo du deine Plugins einrichtest gibt es eine Textbox in die du alle validen Actions für dieses Plugin schreiben kannst. Da dürftest du auch schon etwas reingeschrieben haben, da soweit ich weiß bei keiner Angabe alle Actions erlaubt sind.

Wenn du den Extension Builder nicht nutzt (was ein Fehler ist! der nimmt dir sehr viel Arbeit ab!) kannst du das in der localconf.php konfigurieren.

Philipp88 schrieb

Ich finde die alte Programmierung war verständlicher bzw. einfacher als Extbase oder ändert sich das noch?

Extbase ist in seinen Grundzügen sehr logisch aufgebaut, wenn du mal verstanden hast warum es was macht und vorallem was es alles automatisch macht wirst du es einfacher haben 😉
Allerdings kam ich mit piBase auch nie zurecht *g* (Ok, musste es glücklicherweiße auch nicht allzulange nutzen)

Philipp88 ·

ok, ich habe es jetzt mit den Extension Builder aktualisiert jetzt geht es🙂

Jetzt habe ich ein Formular was in etwa so aussieht:

<f:form action="cform" name="person">
  <table>
    <tr>
      <td>Name</td>
      <td><f:form.textfield property="name" /></td>
    </tr>
    <tr>
      <td>Vorname</td>
      <td><f:form.textfield property="vorname" /></td>
    </tr>
    <tr>
      <td>Kurze Beschreibung</td>
      <td><textarea name="tx_people_people[desc]" cols="10" rows="5"></textarea></td>
    </tr>
    <tr>
      <td colspan="2"><input type="submit" name="tx_people_people[send]" value="Benutzer anlegen" /></td>
    </tr>
  </table>
  </f:form>

Ich versuche jetzt mittels Extbase an die variablen (post) heranzukommen:

public function cformAction($person) {
          \t3lib_utility_Debug::debug($person, 'person');
	}

leider ohne erfolg🙁

Kannst du bitte nochmal helfen?

karf ·

Damit extbase dir ein Objekt erstellt musst du das im <f:form> angeben.

In deinem Fall würde das jetzt so aussehen

<f:form action="cform" name="person" object="{person}">

ich bin mir nicht sicher ob du vorher {person} selbst erzeugen musst. Schaden tut es sicherlich nicht 😉

Es gibt übrigens auch einen <f:form.textarea /> ViewHelper.

(Basic Viewhelper sind alle hier aufgelistet: http://wiki.typo3.org/Fluid)

Philipp88 ·

Hi,

ich habe jetzt den Formular object="{Person}" mitgegeben, leider ist die Variable immer noch leer🙁

Was meinst du mit object selber anlegen?

karf ·

In der dazugehörigen Action eine neue Instanz von Person erstellen

$person = $this->objectManager->create('\Dein\Model\Person');

und an den View übergeben.

$this->view->assign('person', $person);

Ich bin mir aber nicht sicher, ob das nötig ist oder dein Problem löst. Aber so mache ich das meistens (Im Normalfall um default Parameter zu setzen)

Morgen oder Montag werde ich aber wahrscheinlich ein neues Formular machen müssen, da schau ich mal nach welche Schritte mindestens nötig sind.

Philipp88 ·

Das wäre nett von dir ich bekomme das einfach nicht zum laufen 🙁

Jetzt kommt folgende Fehlermeldung:

1253175643: The argument type for parameter $person of method TYPO3\People\Controller\PersonenController->cformAction() could not be detected.

Bei diesen PHP- Code:

/**
	 * action cform
	 *
	 * @return void
	 */
	public function cformAction($person) {
          $person = $this->objectManager->create('\TYPO3\People\Domain\Model\Personen');
          
          $this->view->assign('person', $person);
	}

Wenn ich bei der Funktion den Parameter weglasse kommt zwar nicht mehr die Fehlermeldung von oben, stattdessen aber ne andere:

Fatal error: Class '\TYPO3\People\Domain\Model\Personen' not found

Das Model gibt es aber ...🙁

Bitte helf mir

Philipp

karf ·
Philipp88 schrieb

Das wäre nett von dir ich bekomme das einfach nicht zum laufen 🙁

Jetzt kommt folgende Fehlermeldung:

1253175643: The argument type for parameter $person of method TYPO3\People\Controller\PersonenController->cformAction() could not be detected.

Bei diesen PHP- Code:

/**
	 * action cform
	 *
	 * @return void
	 */
	public function cformAction($person) {
          $person = $this->objectManager->create('\TYPO3\People\Domain\Model\Personen');
          
          $this->view->assign('person', $person);
	}

Du musst den Parameter noch als Annotation in den Header eintragen.
also
@param \TYPO3\People\Domain\Model\Personen $person
in die Zeile vor dem @return

Philipp88 schrieb

Wenn ich bei der Funktion den Parameter weglasse kommt zwar nicht mehr die Fehlermeldung von oben, stattdessen aber ne andere:

Fatal error: Class '\TYPO3\People\Domain\Model\Personen' not found

Das Model gibt es aber ...🙁

Bitte helf mir

Philipp

Sorry das war ein Fehler in meinem Beispiel. Wenn du Klassennamen an eine Typo3 Funktion übergibst, immer ohne den ersten / vom Namespace. Also nur 'TYPO3\People\Domain\Model\Personen'

Du solltest aber vorher noch überprüfen ob nicht ein Objekt übergeben wurde, ansonsten macht der Parameter ja keinen Sinn und du würdest immer mit einem frischen Objekt beginnen. (oder ist das gewollt?)

if ($person == null)
{
    $person = $this->objectManager->create('TYPO3\People\Domain\Model\Personen');
}
Philipp88 ·

hast du schon etwas herrausfinden können? Bei mir funzt es einfach nicht 🙁

Mal was anderes:

Ich sitze jetzt an einer anderen Extension, wo mehrere Bilder ein Datensatz zugeordnet sind und diese in der Singleansicht ausgegeben werden sollen.

Erstmal der Code:

Controller:

...
public function showAction(\TYPO3\Project\Domain\Model\Project $project) {
    $project_id = $this->request->getArgument('project');
    $this->view->assign('project', $project);
    $this->view->assign("path", "uploads/tx_project");

    $images = $this->projectRepository->get_images($project_id);    
    #print_r($images);
    
    $this->view->assign("images", $images);
    
  }

Repository:

public function showAction(\TYPO3\Project\Domain\Model\Project $project) {
    $project_id = $this->request->getArgument('project');
    $this->view->assign('project', $project);
    $this->view->assign("path", "uploads/tx_project");

    $images = $this->projectRepository->get_images($project_id);    
    #print_r($images);
    
    $this->view->assign("images", $images);
    
  }

Ergebnis soll in Template erscheinen:

<f:for each="{images}" as="image">
          {image.image}
        </f:for>

Leider kommt dann folgende Fehlermeldung 🙁

Cannot cast object of type "TYPO3\CMS\Extbase\Persistence\ObjectStorage" to string.

Was ist den da falsch?

Kannst Du oder jemand anderes mir helfen?
Philipp