Zum Inhalt springen

Zugriff auf übergeordnete Objekt-Attribute im Action-Controller

Erstellt am 1. Oktober 2014 · 6 Antworten · letzte Antwort am 8. Oktober 2014

Tags: Frage

Dschungel-Tiger ·

Hallo zusammen,
ich habe ein Extension-Model mit z.B. drei verschiedenen Klassen. Sagen wir:

  • Fortbewegungsmittel

  • Auto

  • BMW

Ausgehend von der Klasse Fortbewegungsmittel sind alle Klassen mit einer 1:n Relation miteinander verknüpft. In einem speziellen ListSpecialBmwAction Controller der Klasse BWM lasse ich mir nur ganz bestimmte BMWs mit einem bestimmten Attribut-Wert ausgeben. Jetzt benötige ich aber auch noch zusätzlich in der dazugehörigen ListSpecialBmw.html einige Attribute der übergeordneten Klasse. Entweder der direkt übergeordneten Klasse Auto, oder sogar von der ersten Klasse Fortbewegungsmittel.

Gibt es hier eine elegante und schnelle Lösung, auf die Attribute übergeordneter Objekte im Action-Controller zuzugreifen oder muss ich mir alle Objekte erst mühsam mittels ihrer uid selbst zusammensuchen?

Unbekannter Benutzer ·

Deine Ausführungen sind etwas verwirrend.
Hast du nun 3 verschiedene Klassen ( Fortbewegungsmittel, Auto, BMW ) die unabhängig voneinander sind (bzw. nur durch Relationen miteinander verknüpft sind? Wenn ja, was ist der Sinn dahinter ? ) ?

Falls ja, kannst du einfach über $bmw->getAuto()->getAttribut() auf das gewünschte attribut von Auto zugreifen.

Oder hast du eine abstrakte Klasse Fortbewegungsmittel, die durch Auto, und die wiederum durch BMW erweitert werden? Falls ja, verstehe ich die 1:n Relationen nicht wirklich, aber in diesem Fall kannst du einfach in der BMW Klasse die getter/setter der übergeordneten Klasse aufrufen.

z.b. $bmw->getAutoAttribut() wobei autoAttribut ein Attribut der Klasse Auto ist.

Aber vielleicht kannst du mich/uns auch ein wenig mehr mit deiner Struktur aufklären, denn entweder ich verstehe absolut nicht, was du da machst, oder es ist quatsch, was du da machst 😉

Dschungel-Tiger ·

Ja, sorry - ich habe da ein wirklich blödes Beispiel verwendet, das man eigentlich mittels Klassenvererbung realisieren sollte und deshalb total verwirrt.

Hier ein konkreteres Beispiel:

Ich habe in meinem Model die

FE_Users

um eigene Felder erweitert, die in meinem Model Klasse

User

heißt. Die hat eine 1:n Relation zu der Klasse

Zertifizierung

, die ihrerseits wiederum eine 1:n Relation zur Klasse

Antrag

hat (eine bestimmte Zertifizierung kann durchaus mehrere Anträge haben).

Jetzt möchte ich im ListAction Controller der Klasse

Antrag

Zugriff auf Felder der Klasse

Zertifizierung

und auch

User

bekommen. Besser wäre natürlich gleich, ich könnte mir das gesamt Objekt holen, so dass ich auf alle Attribute Zugriff habe und diese dem View mit assign zusätzlich zuweisen kann.

Standardmäßig generiert mir der Extension_Builder ja schon die get/set Methoden, um auf die nachgelagerten Objekte Zugreifen zu können, aber ich finde momentan keine Beschreibung, wie ich auf die Attribute/Objekte der übergeordneten Klassen im ListAction Controller zugreifen kann. Entweder sehe ich einfach den Wald vor lauter Bäume nicht mehr, oder aber es ist doch nicht so trivial möglich.;-(

Unbekannter Benutzer ·

Okay, ich verstehe 😉

Also das hängt nun ein bisschen davon ab, wie deine 1:n Relation konstruiert ist.

Fall A) Beide Objekte "wissen" von der Relation. D.h. du könntest die Zertifzierung beim User sehen und zuweisen, du könntest aber auch den User bei der Zertifizierung sehen/zuweisen. Beide wissen sozusagen voneinander.

Fall B) Lediglich eines deiner Objekte trägt die Relation. D.h. du kannst in einer Zertifizierung einen User sehen, hinzufügen, aber dieser User weiß gar nicht, bzw. bekommt gar nicht mit, dass er zugeordnet wurde und speichert diese Information dementsprechend auch gar nicht.

(Sorry für die wenig fachliche Grammatik, ich versuch es mal umgangssprachlich zu erklären 😉 )

Für Fall A)
Hier ist es einfach, hier kannst du einfach im Controller über die Funktion $antragsObjekt->getZertifizierung() dein/e Zertifizierungsobjekt/e erhalten. Weitergehend dann mit $antragsObjekt->getZertifizierung()->getUser() ( vereinfacht dargestellt, natürlich musst du ObjectStorages berücksichtigen etc. )

Für Fall B)
Würde ich alles daransetzen, Fall A eintreten zu lassen 😉
Dafür müsstest du eigentlich nur die gegenüberliegenden Relationen in den entsprechenden Models anpassen.
Wenn du also in deinem Antrag ein Feld für Zertifizierungen hast, dann musst du entsprechend bei der Zertifizierung ein Feld für Antrag anlegen.

Ich hoffe, das hilft dir ein wenig weiter, wenns auch nicht grad sehr detailliert ist 😉
Ansonsten frag nochmal nach oder schreib mir ne PM

Dschungel-Tiger ·

Genau, in meiner Klasse User gibt es eine Methode getZertifizierungen(), die mir Zugriff alle Zertifizierungsobjekte des aktuellen Users bietet (kann mit foreach() iteriert weren). Auch in der Klasse Zertifizierung gibt es eine Methode getAntraege(), die mir alle Antragsobjekte der aktuellen Zertifizierung liefert. Aber hier habe ich leider keine Methode, die mir das User-Objekt wieder zurückliefert (wie z.B. getUser()). Aber genau eine solche Methode benötige ich und habe leider immer noch nirgendwo gefunden (6 verschiedene Bücher und Internet-Foren), wie ich sie in der Klasse Zertifizierung schreiben muss. Derzeit sehen meine Klassen ausschnittsweise in etwa so aus:

<?php
namespace STZ\Wta\Domain\Model;
/**
 * User
 */
class User extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser {

	/**
	 * User Name
	 *
	 * @var string
	 * @validate NotEmpty
	 */
	protected $username = '';

	/**
	 * User Group
	 *
	 * @var string
	 * @validate NotEmpty
	 */
	protected $usergroup = '';

...

	/**
	 * Relation User-Certification
	 *
	 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Certification>
	 * @cascade remove
	 * @lazy
	 */
	protected $relUserCertification = NULL;

	/**
	 * __construct
	 */
	public function __construct() {
		//Do not remove the next line: It would break the functionality
		$this->initStorageObjects();
	}

	/**
	 * Initializes all ObjectStorage properties
	 * Do not modify this method!
	 * It will be rewritten on each save in the extension builder
	 * You may modify the constructor of this class instead
	 *
	 * @return void
	 */
	protected function initStorageObjects() {
		$this->relUserCertification = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
	}

	/**
	 * Returns the username
	 *
	 * @return string $username
	 */
	 public function getUsername() {
 		return $this->username;
	 }

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

  	/**
 	 * Returns the usergroup
	 *
 	 * @return string $usergroup
	 */
 	public function getUsergroup() {
		return $this->usergroup;
	 }

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

...

	/**
	 * Adds a Certification
	 *
	 * @param \STZ\Wta\Domain\Model\Certification $relUserCertification
	 * @return void
	 */
	public function addRelUserCertification(\STZ\Wta\Domain\Model\Certification  $relUserCertification) {
		$this->relUserCertification->attach($relUserCertification);
	}

	/**
	 * Removes a Certification
	 *
	 * @param \STZ\Wta\Domain\Model\Certification $relUserCertificationToRemove The Certification to be removed
	 * @return void
	 */
	public function removeRelUserCertification(\STZ\Wta\Domain\Model\Certification $relUserCertificationToRemove) {
		$this->relUserCertification->detach($relUserCertificationToRemove);
	}

	/**
	 * Returns the relUserCertification
	 *
	 * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Certification> $relUserCertification
	 */
	public function getRelUserCertification() {
		return $this->relUserCertification;
	}

	/**
	 * Sets the relUserCertification
	 *
	 * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Certification> $relUserCertification
	 * @return void
	 */
	public function setRelUserCertification(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relUserCertification) {
		$this->relUserCertification = $relUserCertification;
	}

}
<?php
namespace STZ\Wta\Domain\Model;

/**
 * Certification
 */
class Certification extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {

    /**
	 * Certification Type
	 *
	 * @var string
	 * @validate NotEmpty
	 */
	protected $certType = '';

...

	/**
	 * Relation Certification-Proposal
	 *
	 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Proposal>
	 * @cascade remove
	 * @lazy
	 */
	protected $relCertificationProposal = NULL;

	/**
	 * __construct
	 */
	public function __construct() {
		//Do not remove the next line: It would break the functionality
		$this->initStorageObjects();
	}

	/**
	 * Initializes all ObjectStorage properties
	 * Do not modify this method!
	 * It will be rewritten on each save in the extension builder
	 * You may modify the constructor of this class instead
	 *
	 * @return void
	 */
	protected function initStorageObjects() {
		$this->relCertificationProposal = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
	}

	/**
	 * Returns the certType
	 *
	 * @return string $certType
	 */
	public function getCertType() {
		return $this->certType;
	}

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

	/**
	 * Adds a Proposal
	 *
	 * @param \STZ\Wta\Domain\Model\Proposal $relCertificationProposal
	 * @return void
	 */
	public function addRelCertificationProposal(\STZ\Wta\Domain\Model\Proposal $relCertificationProposal) {
		$this->relCertificationProposal->attach($relCertificationProposal);
	}

	/**
	 * Removes a Proposal
	 *
	 * @param \STZ\Wta\Domain\Model\Proposal $relCertificationProposalToRemove The Proposal to be removed
	 * @return void
	 */
	public function removeRelCertificationProposal(\STZ\Wta\Domain\Model\Proposal $relCertificationProposalToRemove) {
		$this->relCertificationProposal->detach($relCertificationProposalToRemove);
	}

	/**
	 * Returns the relCertificationProposal
	 *
	 * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Proposal> $relCertificationProposal
	 */
	public function getRelCertificationProposal() {
		return $this->relCertificationProposal;
	}

	/**
	 * Sets the relCertificationProposal
	 *
	 * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\STZ\Wta\Domain\Model\Proposal> $relCertificationProposal
	 * @return void
	 */
	public function setRelCertificationProposal(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relCertificationProposal) {
		$this->relCertificationProposal = $relCertificationProposal;
	}

}

In der Klasse Zertifizierung (Certification) gibt es jetzt aber keine Methode (z.B. getUser), die mir das übergeordnete User-Objekt zurück gibt. Und genau diese versuche ich schon die ganze Zeit zu implementieren, habe leider aber immer noch nicht die korrekte Lösung dafür finden können.

Unbekannter Benutzer ·

Du musst deine Klasse Certification um die Methode getUser erweitern 😉
Grundlage dafür ist, dass du auch das TCA entsprechend angepasst hast.

Es sieht also danach aus, als handele es sich bei dir um oben genannten Fall B).

Du musst also in deinem TCA für die Certification ein Feld für User anlegen, damit du vom Zertifikat auf den User zugreifen kannst. Aktuell ist es bei dir so konfiguriert, dass quasi nur der User von dem Zertifikat weiß, das Zertifikat allerdings nichts davon, dass es dem User zugeordnet ist.

Du musst also in deinem TCA das entsprechende Feld ergänzen, und die entsprechenden Settings dafür beachten. So eine Relation könnte beispielhaft so aussehen:

Im Model PaintRelations

'cluster' => array(
	'exclude' => 1,
	'label' => 'Related Cluster',
	'config' => array(
		'type' => 'group',
		'internal_type' => 'db',
		'allowed' => 'tx_sb_domain_model_cluster',
		'foreign_table' => 'tx_sb_domain_model_cluster',
		'MM' => 'tx_sb_cluster_clusterpaint_mm',
		'size' => 1,
		'autoSizeMax' => 1,
		'maxitems' => 1,
		'multiple' => 0,
		'selectedListStyle' => 'width:250px;',
		'wizards' => array(
			'_PADDING' => 5,
			'_VERTICAL' => 1,
		'suggest' => array(
			'type' => 'suggest',
			),
		),
	),
),

=> Im Model Cluster

'paint_relations' => array(
	'exclude' => 1,
	'label' => 'Paint-Relations',
	'config' => array(
		'type' => 'inline',
		'internal_type' => 'db',
		'allowed' => 'tx_sb_domain_model_clusterpaint',
		'foreign_table' => 'tx_sb_domain_model_clusterpaint',
		'MM' => 'tx_sb_cluster_clusterpaint_mm',
		'MM_opposite_field' => 'cluster',
		'size' => 100,
		'autoSizeMax' => 30,
		'maxitems' => 9999,
		'multiple' => 0,
		'selectedListStyle' => 'width:250px;',
		'wizards' => array(
			'_PADDING' => 5,
			'_VERTICAL' => 1,
			'suggest' => array(
				'type' => 'suggest',
			),
		),
	),
),

Dazu brauchst du natürlich für deine Relation eine MM-Tabelle, die die Relationen beinhaltet.
Über diese Relationstabelle werden dann die Relationen aufgelöst ( uid zu foreign uid und umgekehrt ).

Zusätzlich musst du natürlich die entsprechenden Felder in der DB-Tabelle anlegen und die entsprechenden Funktionen in deinen Klassen ergänzen.

Im Beispiel im Model Cluster:

	/**
	 * paintRelations
	 *
	 * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Sb_Domain_Model_ClusterPaint>
	 * @lazy
	 */
	protected $paintRelations;

	/**
	 * Adds a paintRelation
	 *
	 * @param Tx_sb_Domain_Model_ClusterPaint $paintRelations
	 * @return void
	 */
	public function addPaintRelations(Tx_sb_Domain_Model_ClusterPaint $paintRelation) {
		$this->paintRelations->attach($paintRelation);
	}

	/**
	 * Removes a paintRelations
	 *
	 * @param Tx_sb_Domain_Model_ClusterPaint $paintRelations The Product to be removed
	 * @return void
	 */
	public function removePaintRelations(Tx_sb_Domain_Model_ClusterPaint $paintRelation) {
		$this->paintRelations->detach($paintRelation);
	}

	/**
	 * Returns the paintRelations
	 *
	 * @return Tx_Extbase_Persistence_ObjectStorage<Tx_sb_Domain_Model_ClusterPaint> $paintRelations
	 */
	public function getPaintRelations() {
		return $this->paintRelations;
	}

	/**
	 * Sets the paintRelations
	 *
	 * @param Tx_Extbase_Persistence_ObjectStorage<Tx_sb_Domain_Model_ClusterPaint> $paintRelations
	 * @return void
	 */
	public function setPaintRelations(Tx_Extbase_Persistence_ObjectStorage $paintRelations) {
		$this->paintRelations = $paintRelations;
	}

hier machst du also eigentlich genau das gleiche, wie du es schon bei deinem Model hast, von dem du auf die andere Klasse zugreifen kannst. Nur in die andere Richtung 😉

Hoffe das hilft dir weiter.

Dschungel-Tiger · · Beste Antwort

Vielen Dank für die Infos. Habe mir jetzt noch die Felder im Model so wie beschrieben angelegt, dass ich auch rückwärts wieder auf die Elternobjekte zugreifen kann. Jetzt funktioniert es 🙂