Zum Inhalt springen

Extension Builder Map to existing table

Erstellt am 25. April 2013 · 1 Antwort · letzte Antwort am 25. April 2013

Tags: Frage

jeipack ·

Hi Forum
Auf der Suche nach Informationen bin ich nun schon öffters in diesem Forum gelandet und nun habe ich beschlossen mich selbst hier anzumelden und hoffe dass ihr mir weiterhelfen könnt 🙂
Ich versuche mich mit dem Extension Builder resp. allgemein mit ExtBase Extensions.
Zwei Testextensions habe ich schon damit gemacht, relativ easy gehalten.
Nun versuche ich mich an einer echten Aufgabenstellung, die etwa so lautet:
Wenn ein Datensatz in tt_content mit einem bestimmten Flag hinzugefügt wird dann greife auf diesen Datensatz zu, lese bodytext aus und mache was damit.
Nun, leider scheitere ich schon beim Zugriff auf die tt_content.

Ich versuche immer ein Problem auf Teilprobleme aufzusplitten und somit versuche ich im Moment nur auf tt_content zuzugreiffen. Was habe ich gemacht?
Mit dem Extension Builder ein neues Model namens Content. Dort bei "Map to existing table" tt_content eingefügt. Ein Property namens "bodytext" hinzugefügt. Und "is aggregate root?" angeklickt. Ein Backendplugin angegeben, sowie ein Frontentplugin(Das aber nur, damit er die html-Templates erstellt). Kurz gespeichert, dann das Frontentplugin wieder rausgenommen und nochmals gespeichert. So, nun noch in ext_tables.sql den Typ des Feldes bodytext von text auf mediumtext gestellt (tt_content.bodytext ist vom Type mediumtext und ich will den Typ ja nicht verändern).

Mein Content Controller sieht so aus:

class Tx_Mybackendtest_Controller_ContentController extends Tx_Extbase_MVC_Controller_ActionController {

	/**
	 * contentRepository
	 *
	 * @var Tx_Mybackendtest_Domain_Repository_ContentRepository
	 */
	protected $contentRepository;

	/**
	 * injectContentRepository
	 *
	 * @param Tx_Mybackendtest_Domain_Repository_ContentRepository $contentRepository
	 * @return void
	 */
	public function injectContentRepository(Tx_Mybackendtest_Domain_Repository_ContentRepository $contentRepository) {
		$this->contentRepository = $contentRepository;
	}

	/**
	 * action list
	 *
	 * @return void
	 */
	public function listAction() {
		$contents = $this->contentRepository->findAll();
		$this->view->assign('contents', $contents);
	}

	/**
	 * action show
	 *
	 * @param Tx_Mybackendtest_Domain_Model_Content $content
	 * @return void
	 */
	public function showAction(Tx_Mybackendtest_Domain_Model_Content $content) {
		$this->view->assign('content', $content);
	}

}

Und die Fehlermeldung wenn ich auf das Modul zugreiffen will sieht so aus:
Fatal error: Call to a member function findAll() on a non-object in /var/www/hosts/mytypo/typo3conf/ext/mybackendtest/Classes/Controller/ContentController.php on line 58

Nun, ehrlich gesagt weiss ich nicht wo diese inject Methoden aufgerufen werden und somit das Repository initialisiert wird. Aber grundsätzlich habe ich nichts anderes gemacht, als wie ich machen würde, würde ich ein eigenes Model/Tabelle erzeugen. Und dort klappt es

Was mir natürlich auffällt ist, dass Configuration\TCA\Content.php leer ist. Ich dachte diese Infos sind nötig, damit ExtBase das mapping zwischen dem Model und der Tabelle machen kann. Aber um ehrlich zu sein bin ich selbst etwas unzufrieden, da alles nur auf Halbwissen basiert. Es gibt zwar zahlreiche Tutorials im Netz, aber alle gehen wieder einen anderen Weg und bauen auf einer anderen Extension Builder Version auf, etc.

Wo genau liegt mein Fehler? Würde mich freuen hier ein bisschen Unterstützung zu finden. Auch an nützlichen Links und allgemeinen Tipps bin ich interessiert 🙂

PS: Versionen
typo3: 4.5.25
ExtBase: 1.3.4
Extension Builder: 2.4.2

Grüsse
jeipack

jeipack ·

Das Problem liegt wirklich daran, dass $this->contentRepository nicht gesetzt ist.

Habe mein Controller und Repository mal diesbezüglich angepasst:
Repository:

class Tx_Mybackendtest_Domain_Repository_ContentRepository extends Tx_Extbase_Persistence_Repository {

 /**
 * Gets all tt_content
 *
 * @return Tx_Extbase_Persistence_QueryResultInterface The contents
 */
 public function getAll() {
	$query = $this->createQuery();
	$query->statement("Select bodytext from tt_content");
	return $query->execute();
 }

}

Controller:

class Tx_Mybackendtest_Controller_ContentController extends Tx_Extbase_MVC_Controller_ActionController {

	/**
	 * contentRepository
	 *
	 * @var Tx_Mybackendtest_Domain_Repository_ContentRepository
	 */
	protected $contentRepository;

	/**
	 * injectContentRepository
	 *
	 * @param Tx_Mybackendtest_Domain_Repository_ContentRepository $contentRepository
	 * @return void
	 */
	public function injectContentRepository(Tx_Mybackendtest_Domain_Repository_ContentRepository $contentRepository) {
		$this->contentRepository = $contentRepository;
	}

	/**
	 * action list
	 *
	 * @return void
	 */
	public function listAction() {
		// $contents = $this->contentRepository->findAll();
		// $this->view->assign('contents', $contents);
		$repo = new Tx_Mybackendtest_Domain_Repository_ContentRepository();
		$contents = $repo->getAll();
		$this->view->assign('contents', $contents);
	}

	/**
	 * action show
	 *
	 * @param Tx_Mybackendtest_Domain_Model_Content $content
	 * @return void
	 */
	public function showAction(Tx_Mybackendtest_Domain_Model_Content $content) {
		$this->view->assign('content', $content);
	}

}

Zusammen mit dem Standard Fluid Template:

<f:layout name="Default" />

This Template is responsible for creating a table of domain objects.

If you modify this template, do not forget to change the overwrite settings
in /Configuration/ExtensionBuilder/settings.yaml:
  Resources:
    Private:
      Templates:
        List.html: keep

Otherwise your changes will be overwritten the next time you save the extension in the extension builder

<f:section name="main">
<h1>Listing for Content</h1>

<f:flashMessages />

<table  class="tx_mybackendtest" >
	<tr>
		<th><f:translate key="tx_mybackendtest_domain_model_content.bodytext" /></th>
		<th> </th>
		<th> </th>
	</tr>

	<f:for each="{contents}" as="content">
		<tr>
			<td><f:link.action action="show" arguments="{content : content}"> {content.bodytext}</f:link.action></td>
			<td><f:link.action action="edit" arguments="{content : content}">Edit</f:link.action></td>
			<td><f:link.action action="delete" arguments="{content : content}">Delete</f:link.action></td>
		</tr>
	</f:for>
</table>

<f:link.action action="new">New Content</f:link.action>
</f:section>

So funktioniert es "fast". in tt_content sind 270 Datensätze.
Wenn listAction() aufgerufen wird, werden auch 270 Einträge in der ListView dargestellt, allerdings immer nur mit dem bodytext aus dem ersten Datensatz. Was ich auch nicht ganz verstehe. Mit "<f:for each="{contents}" as="content">" müsste er doch immer den nächsten Datensatz im Array nehmen.
Edit --> füge ich beim SQL noch die uid dazu, funktioniert es:
"SELECT `uid`, bodytext FROM tt_content"
Anscheinend braucht er eine ID, wieso genau kann ich aber auch nicht sagen.

Und natürlich wäre diese Lösung nur ein Workaround und sicherlich nicht die saubere Variante.