Zum Inhalt springen

Extbase 6.0 Model erweitern

Erstellt am 12. März 2013 · 11 Antworten · letzte Antwort am 14. August 2013

Tags: Frage

kjuuze ·

Hallo,

TYPO3 6.0.4
Extbase 6.0.0

Ich möchte eine (vorerst nur eine Test-) Extension um ein Feld erweitern. Dazu habe ich mit dem Extension Builder eine weitere Extension angelegt. Dort die zu erweiternde Tabelle und das Model angegeben. Die Datenbank wird richtig um die Felder "meinFeld" und "tx_extbase_type" erweitert. Wird im BE der ExtbaseType umgestellt, kann das neue Feld auch korrekt befüllt werden. Nur die Ausgabe im Frontend klappt (noch) nicht. Meine Vermutung, es liegt am Mapping im Typoscript. Der Extension Builder erstellt folgendes Script:

VendorName: Alpgis,
Model: Poi,
zu erweiternde Ext: Test,
neue Ext: golf

config.tx_extbase {
	persistence {
		classes {
			Alpgis\Test\Domain\Model\Poi {
				subclasses {
					Tx_Golf_Poi =

				}
            }
             {
                mapping {
                    tableName = tx_test_domain_model_poi
                    recordType = Tx_Golf_Poi
                }
            }
            
    	}
    }
}

Dies bringt folgende Fehlermeldung: No class name was given to retrieve the Data Map for.
Vergebe ich bei "Tx_Golf_Poi =" eine Klasse, kriege ich keine FE-Ausgabe mehr.

Hat jemand von euch Erfahrungen damit und kann mir den ein oder anderen Tipp geben? Vielen Dank!

kjuuze ·

Rollen wir das Ganze mal von vorne auf... was braucht man, um mit ext2 die ext1 um ein feld zu erweitern und dies per Fluid ausgeben zu können?

1. DB-Feld (Feld und tx_extbase_type, zB mit Hilfe von Extension Builder)
2. Model, welches das Model der ext1 "extended" (auch zB mit Hilfe von Extension Builder)

...richtig so weit? wie weiter? (TypoScript? Controller? Repository? ext_tables.php?)

kjuuze ·

Aktuelle Erkenntnis: Traue nicht dem Extension Builder! Dieser generiert in v2.5.1 ein völlig anderes ext_tables.php als in v2.5.2. Und ich finde einfach die Lösung nicht, für ein - wie ich denke triviales - Problem.

Kann mir jemand ein funktionierendes Beispiel nennen, indem eine Extbase-Extension eine vorhandene Extbase-Klasse und deren DB-Tabelle erweitert und die Daten im FE ausgegeben werden können? Ich seh momentan gar nicht mehr durch... #angry# ich möchte die "Original"-Klasse, wenn irgendwie möglich, nicht anfassen.

Danke vielmals!

harald1972 ·

Die Erkenntnis ist schonmal gut 🙂 (Traue nicht dem Extension Builder!)

Ich nutze noch TYPO3 v4.5 und den ExtensionBuilder 2.4.0
... daher weiß ich nicht, ob mein Wissen deinem Problem dient...

Ich weiß: einbinden externer Klassen geht damit garnicht.
Relationen innerhalb der eigenen Domäne müssen nach dem Kickstart noch editiert werden.
Bisher ist allerdings fe_user die einzige externe von mir genutzte Tabelle.
Extbase hat ja dafür auch schon eine eigene Klasse: Tx_Extbase_Domain_Model_FrontendUser.
Die nutze ich, wie sie ist. Ich hab die nicht aufgebohrt

Zuerst würde ich mir die ext_tables.SQL anschauen. Der ExtensionManager erzeugt gern doppelte Einträge.
Die gewünschten DB-Tabellen und deren Spalten müssen hier drin sein!
(so wie ich das bei dir lese, tut dieser Teil schon)
Solange die Eingabe nur über FE erfolgt, ist die TCA-Config (ext_tables.php) auch uninteressant.

Die Erweiterung des Models um das Attribut, muss logischerweise in deinNeuesModel.php

Ich hab nicht verstanden, was genau in deinem FE nicht zu sehen ist. Die View muss natürlich wissen, daß es sich um das erweiterte Model handelt, um die richtigen Attribute lesen zu können und es richtig anzuzeigen. Und jeder View muss immer tapfer alles übergeben werden, was sie braucht. Dieser Punkt wird gern bei der Verwendung von Partials vergessen.

Gruß Harald

kjuuze ·

Ja, die TCA-Config krieg ich soweit hin. Im Backend habe ich das neue Feld, sowie "tx_extbase_type". Trage ich im neuen Feld Daten ein, werden die auch brav in die DB gespeichert und auch wieder ausgelesen.

Was noch nicht klapp, ist die Erweiterung des Models. Das Model sieht folgendermassen aus:

class Model2 extends \Vendor\Ext1\Domain\Model\Model {

	/**
	 * additional
	 *
	 * @var \string
	 */
	protected $additional;

	/**
	 * Returns the additional
	 *
	 * @return \string $additional
	 */
	public function getAdditional() {
		return $this->additional;
	}

	/**
	 * Sets the additional
	 *
	 * @param \string $additional
	 * @return void
	 */
	public function setAdditional($additional) {
		$this->additional = $additional;
	}

}

Nur kriege ich das ganze jetzt nicht ins Fluid-Template. Erweitere ich das "original" Model per Hand um obenstehende Code, klappt es problemlos. Also ist mein Verdacht, dass das Model gar nicht wirklich erweitert wird. Denn auch ein Debug im Fluidtemplate gibt das neue Feld noch nicht aus. Mapping im TS falsch?!

config.tx_extbase {
        persistence {
                classes {
			Vendor\Ext1\Domain\Model\Model {
                                subclasses {
                                        Vendor\Ext2\Domain\Model\Model2 = Vendor\Ext2\Domain\Model\Model2
                                }
                        }
			Vendor\Ext2\Domain\Model\Model2 {
                                mapping {
                                        recordType = Vendor\Ext2\Domain\Model\Model2
                                        tableName = tx_ext1_domain_model_model
                                }
                        }
                }
        }
}

So hab ich das aus blog_example 6.0 abgeschaut. Hier

Die View muss natürlich wissen, daß es sich um das erweiterte Model handelt, um die richtigen Attribute lesen zu können und es richtig anzuzeigen

Klar, nur wie bring ich Ihr das bei? ;-)

harald1972 ·

Nun... das oft zitierte BlogExample hab ich nicht gemacht.

Ich kenn mich auch nicht so richtig gut aus mit TS-Config.
Wenn's tut ist gut 😉

Ich hab bei mir hier sowas:

plugin.tx_myext.persistence.classes {
  Tx_Myext_Domain_Model_SubClass.mapping.tableName = tx_myext_domain_model_parentclass
}

auf dein Model übertragen sollte das dann so aussehen:

plugin.tx_ext2.persistence.classes {
  Tx_Ext2_Domain_Model_Model.mapping.tableName = tx_ext1_domain_model_model
}

Erweitere ich das "original" Model per Hand um obenstehende Code, klappt es problemlos.

Wo ist dann das Problem?

kjuuze ·

"Erweitere ich das "original" Model per Hand um obenstehende Code, klappt es problemlos."

Wo ist dann das Problem?

Ich will das Model der zu erweiternden Extension nicht "manuel" abändern, sondern nur mit einer zweiten Extension erweitern (Updatesicherheit).

Habe es nun endlich hin bekommen. Ich glaube ein fehlender Backslash am Anfang der zu erweiternden Klasse im neuen Model hat mich schier in den Wahnsinn getrieben. Desweiteren scheint mir die vom Extension Builder 2.5.2 generierte ext_tables.php nicht brauchbar. Diejenige von v2.5.1 jedoch schon. Bei der setup.txt verhält es sich genau anders rum...

Ich habe nun noch einmal zwei Extensions erstellt und teile hier die nötigen Files von Extension2, welche Extension1 um ein Feld erweitert. Typo3 läuft momentan in Version 6.0.4.

Die Files von Extension1 sind wohl uninteressant. Die Extension heisst "Extension1" hat den VendorName "Vendor", den Extension-Key "ext1" und ein Model "Model1" mit einem Feld "field1".

Nun zur relevanten Extension2:
Name: Extension2
VendorName: Vendor
Key: ext2
Model: Model2 (erweitert Model1)
Feld: field2

Hier die relevanten Files:

Classes/Domain/Model/Model2.php:

<?php
namespace Vendor\Ext2\Domain\Model;

/***************************************************************
 *  Copyright notice
 *
 *  (c) 2013 
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/

/**
 *
 *
 * @package ext2
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later
 *
 */
class Model2 extends \Vendor\Ext1\Domain\Model\Model1 {

	/**
	 * field2
	 *
	 * @var \string
	 */
	protected $field2;

	/**
	 * Returns the field2
	 *
	 * @return \string $field2
	 */
	public function getField2() {
		return $this->field2;
	}

	/**
	 * Sets the field2
	 *
	 * @param \string $field2
	 * @return void
	 */
	public function setField2($field2) {
		$this->field2 = $field2;
	}

}
?>

Configuration/TypoScript/setup.txt

config.tx_extbase{
    persistence{
        classes{
            Vendor\Ext1\Domain\Model\Model1 {
                subclasses {
                    Tx_Ext2_Model2 = Vendor\Ext2\Domain\Model\Model2
          		}
            }
            Vendor\Ext2\Domain\Model\Model2 {
                mapping {
                    tableName = tx_ext1_domain_model_model1
                    recordType = Tx_Ext2_Model2
                }
            }  
    	}
    }
}

ext_tables.php

<?php
if (!defined('TYPO3_MODE')) {
	die ('Access denied.');
}

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript', 'Extension2');
\TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA('tx_ext1_domain_model_model1');

if (!isset($TCA['tx_ext1_domain_model_model1']['ctrl']['type'])) {
	// no type field defined, so we define it here. This will only happen the first time the extension is installed!!
	$TCA['tx_ext1_domain_model_model1']['ctrl']['type'] = 'tx_extbase_type';
	$tempColumns = array();
	$tempColumns[$TCA['tx_ext1_domain_model_model1']['ctrl']['type']] = array(
		'exclude' => 1,
		'label'   => 'LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext2_domain_model_model2.tx_extbase_type',
		'config' => array(
			'type' => 'select',
			'items' => array(
				array('LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext2_domain_model_model2.tx_extbase_type.0','0'),
			),
			'size' => 1,
			'maxitems' => 1,
			'default' => 'Tx_Ext2_Model2'
		)
	);
	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tx_ext1_domain_model_model1', $tempColumns, 1);
}

$TCA['tx_ext1_domain_model_model1']['types']['Tx_Ext2_Model2']['showitem'] = $TCA['tx_ext1_domain_model_model1']['types']['1']['showitem'];
$TCA['tx_ext1_domain_model_model1']['columns'][$TCA['tx_ext1_domain_model_model1']['ctrl']['type']]['config']['items'][] = array('LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext2_domain_model_model2','Tx_Ext2_Model2');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tx_ext1_domain_model_model1', $TCA['tx_ext1_domain_model_model1']['ctrl']['type'],'','after:hidden');


$tmp_ext2_columns = array(

	'field2' => array(
		'exclude' => 0,
		'label' => 'LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext2_domain_model_model2.field2',
		'config' => array(
			'type' => 'input',
			'size' => 30,
			'eval' => 'trim'
		),
	),
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tx_ext1_domain_model_model1',$tmp_ext2_columns);

$TCA['tx_ext1_domain_model_model1']['columns'][$TCA['tx_ext1_domain_model_model1']['ctrl']['type']]['config']['items'][] = array('LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext1_domain_model_model1.tx_extbase_type.Tx_Ext2_Model2','Tx_Ext2_Model2');

$TCA['tx_ext1_domain_model_model1']['types']['Tx_Ext2_Model2']['showitem'] = $TCA['tx_ext1_domain_model_model1']['types']['1']['showitem'];
$TCA['tx_ext1_domain_model_model1']['types']['Tx_Ext2_Model2']['showitem'] .= ',--div--;LLL:EXT:ext2/Resources/Private/Language/locallang_db.xlf:tx_ext2_domain_model_model2,';
$TCA['tx_ext1_domain_model_model1']['types']['Tx_Ext2_Model2']['showitem'] .= 'field2';

?>

ext_tables.sql

#
# Table structure for table 'tx_ext1_domain_model_model1'
#
CREATE TABLE tx_ext1_domain_model_model1 (

	field2 varchar(255) DEFAULT '' NOT NULL,

	tx_extbase_type varchar(255) DEFAULT '' NOT NULL,

);

Ich hab dann einfach die Templates von Extension1 in das Verzeichnis von Extension2 kopiert, um die gewünschten Felder erweitert und in Configuration/TypoScript/constants.txt die Template-Pfade für das Plugin von Extension1 angepasst. Funktioniert nun soweit einwandfrei, ist jedoch noch nicht bis ins Detail getestet. Wüsste jedoch nicht, was noch schief gehen sollte 😉

Ich hoffe, dass dies dem Ein oder Anderen die Zeit erspart, welche ich dafür gebraucht habe.

Grüsse
Kjuuze

harald1972 ·

Habe es nun endlich hin bekommen. Ich glaube ein fehlender Backslash am Anfang der zu erweiternden Klasse im neuen Model hat mich schier in den Wahnsinn getrieben.

Schön, freut mich für dich, wenn du es auch ohne meine Hilfe hinkriegst 😉

Diese Backslash-Notation ist mir nicht so geläufig, verwende ich nicht. Bei mir sieht das (besipielhaft) immer so aus:

class Tx_MyExt_Domain_Model_Foobar extends Tx_Extbase_DomainObject_AbstractEntity
kjuuze ·

Das sind die Namespaces, welche mit Typo3 CMS 6.0.0 eingeführt wurden und die alten Klassennamen ablösen (werden). Wenn du noch auf 4.5 entwickelst, hat dich das wohl bis anhin auch noch nicht kümmern müssen 😉 Ausschnitt aus dem Mittwaldblog: (Link)

Namespaces

Der komplette TYPO3-Core wurde auf PHP 5.3 Namespaces umgestellt; es gibt also keine Klassennamen mehr. Dabei mussten circa 1.800 Klassennamen verändert werden. Jede Klasse hat einen neuen Namen und einen anderen Platz innerhalb des Dateisystems erhalten. Es wurde darauf geachtet, dass es eine Rückwärtskompatibilitäts-Schicht für die alten Klassen gibt. Alle Extensions sollten problemlos auch ohne Modifikation weiterhin funktionieren.

Beispiel für eine neue Klasse von CssStyledContent:

\TYPO3\CMS\CssStyledContent\Controller (vorher: typo3/sysext/css_styled_content/Classes/Controller)

Die Einführung von Namespaces war eine große und aufwändige Änderung für den gesamten TYPO3-Core.

einpraegsam.​net ·

Trotz der wirklich guten und ausführlichen Beschreibung von kjuuze, bekomme ich das unter TYPO3 6.1.1 nicht zum Laufen - wäre daher für jeden Tipp dankbar.

Habe eine einfache Extension erstellt - mit einem simplen Model mit einem Titel Feld:

namespace TYPO3\Test\Domain\Model;

class Address extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {

	/**
	 * title
	 *
	 * @var \string
	 */
	protected $title;

	/**
	 * Returns the title
	 *
	 * @return \string $title
	 */
	public function getTitle() {
		return $this->title;
	}

	/**
	 * Sets the title
	 *
	 * @param \string $title
	 * @return void
	 */
	public function setTitle($title) {
		$this->title = $title;
	}

}

Aufgabe - Weitere Extension erstellen, die das vorhandene Model um ein weiteres Feld (in meinem Fall subtitle) erweitert.

Model 2

namespace TYPO3\Test2\Domain\Model;

class Address2 extends \TYPO3\Test\Domain\Model\Address {

	/**
	 * subtitle
	 *
	 * @var \string
	 */
	protected $subtitle;

	/**
	 * Returns the subtitle
	 *
	 * @return \string $subtitle
	 */
	public function getSubtitle() {
		return $this->subtitle;
	}

	/**
	 * Sets the subtitle
	 *
	 * @param \string $subtitle
	 * @return void
	 */
	public function setSubtitle($subtitle) {
		$this->subtitle = $subtitle;
	}

}

Versucht in der ext_typoscript_setup.txt der zweiten Extension bzw. direkt im Backend:

config.tx_extbase{
    persistence{
        classes{

            TYPO3\Test\Domain\Model\Address {
                subclasses {
                    Tx_Test2_Address2 = TYPO3\Test2\Domain\Model\Address2
		}
            }
            TYPO3\Test2\Domain\Model\Address2 {
                mapping {
                    tableName = tx_test_domain_model_address
                    recordType = Tx_Test2_Address2
                }
            }
    	}
    }
}

ext_tables.php und ext_tables.sql in Extension 2 habe ich auch eingebaut - das neue Feld steht im Backend zur Verfügung - dort lassen sich auch Werte speichern.

$tmp_test2_columns = array(

	'subtitle' => array(
		'exclude' => 0,
		'label' => 'LLL:EXT:test2/Resources/Private/Language/locallang_db.xlf:tx_test2_domain_model_address2.subtitle',
		'config' => array(
			'type' => 'input',
			'size' => 30,
			'eval' => 'trim'
		),
	),
);

t3lib_extMgm::addTCAcolumns('tx_test_domain_model_address',$tmp_test2_columns);


\TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA('tx_test_domain_model_address');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tx_test_domain_model_address', $tmp_test2_columns, 1);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tx_test_domain_model_address',  'subtitle');

Wo liegt der Denkfehler?

einpraegsam.​net ·

ok, habe die Lösung - der Extbase Type ist scheinbar auch in TYPO3 6.1.1 noch zwingend erforderlich 🙁

Ich will die Auswahl im Backend allerdings nicht haben, also blende ich den Selektor aus.

Hier die Zusammenfassung, wie es bei mir funktioniert

ext_typoscript_setup.txt

plugin.tx_test {
	persistence{
		classes{
			TYPO3\Test\Domain\Model\Address {
				subclasses {
					0 = TYPO3\Test2\Domain\Model\Address2
				}
			}
			TYPO3\Test2\Domain\Model\Address2 {
				mapping {
					tableName = tx_test_domain_model_address
					recordType = 0
				}
			}
		}
	}
}

ext_tables.sql

CREATE TABLE tx_test_domain_model_address (
	subtitle varchar(255) DEFAULT '' NOT NULL,
	tx_extbase_type varchar(255) DEFAULT '0' NOT NULL,
);

Model

class Address extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {

	/**
	 * title
	 *
	 * @var \string
	 */
	protected $title;

	/**
	 * Returns the title
	 *
	 * @return \string $title
	 */
	public function getTitle() {
		return $this->title;
	}

	/**
	 * Sets the title
	 *
	 * @param \string $title
	 * @return void
	 */
	public function setTitle($title) {
		$this->title = $title;
	}

}

ext_tables.php

\TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA('tx_test_domain_model_address');
$TCA['tx_test_domain_model_address']['ctrl']['type'] = 'tx_extbase_type';

$tmp_test2_columns = array(
	'subtitle' => array(
		'exclude' => 0,
		'label' => 'LLL:EXT:test2/Resources/Private/Language/locallang_db.xlf:tx_test2_domain_model_address2.subtitle',
		'config' => array(
			'type' => 'input',
			'size' => 30,
			'eval' => 'trim'
		),
	),
	'tx_extbase_type' => array(
		'config' => array(
			'type' => 'input',
			'default' => '0'
		)
	)
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tx_test_domain_model_address', $tmp_test2_columns, 1);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tx_test_domain_model_address',  'subtitle');
Phil98 ·

Hallo,

ich versuche gerade ebenfalls ein bestehendes Model einer anderen Extension (unter TYPO3 6.1.x.) zu erweitern, habe aber leider noch ein paar Probleme:

Im Backend und in der Datenbank passt soweit alles, die neuen Felder werden angezeigt und die Daten gespeichert. Probleme habe ich leider beim Model. Die neuen getter und setter werden leider nicht eingebunden. Wenn ich diese in das Model der Ziel-Extension kopiere läuft alles, war aber natürlich nicht Ziel der Sache da ich mir das erweitern dann ja auch sparen könnte 😉

Hat vielleicht noch jemand einen Ansatzpunkt? Vorgegangen bin ich nach der Anleitung von einpraegsamnet. Danke an dieser Stelle noch mal für die guten Beschreibungen 🙂