Zum Inhalt springen

FAL und Extbase

Erstellt am 10. Dezember 2012 · 10 Antworten · letzte Antwort am 19. Februar 2013

Tags: Frage

Stargast ·

Hallo,
ich aktualisiere gerade eine meiner Extensions und möchte diese auf den FAL aufbauen.
Derzeit scheint das noch als "experimental" gekennzeichnet zu sein... trotzdem möchte ich mich mal daran versuchen. 🙂

Für meine Extension benötige ich eine Referenz auf einen Folder und mehrere auf jeweils ein Bild. Das Bild-Model muss außerdem noch weitere Daten aufnehmen können.

Mir ist jetzt nur etwas unklar, wie ich da überhaupt anfang...
Ich hab mir gedacht ich leite mein Bild-Model von der Klasse TYPO3\CMS\Extbase\Domain\Model\FileReference ab und erweitere dieses um meine benötigten zusätzlichen Daten.
Ist es dann schlau die Tabelle sys_file_reference um diese Felder zu erweitern? Oder gibts da eine elegantere Lösung?

Gibts dazu schon Beispiele und/oder Erfahrungen?

Danke im Voraus!
MfG Andreas

MajPay ·

Hi

Habe ebenfalls in einem meiner Models ein ObjectStorage, in dem ich Bildreferenzen speichern möchte. Nun habe ich angenommen, dass ich so vorgehe:

/**
	 * Set images
	 * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $images
	 * @return void
	 */
	public function setImages(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $images) {
		$this->images = $images;
	}
	
	/**
	 * Get the images related to this regional object
	 * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage with \TYPO3\CMS\Extbase\Domain\Model\FileReference instances
	 */
	public function getImages() {
		return $this->images;
	}
	
	/**
	 * Add an image to this regional object
	 * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
	 * @return void
	 */
	public function addImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) {
		$this->images->attach($image);
	}
	
	/**
	 * Remove one image from this regional object
	 * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
	 * @return void
	 */
	public function removeImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) {
		$this->images->detach($image);
	}
	
	/**
	 * Remove all images from this regional object
	 * @return void
	 */
	public function removeAllImages() {
		$this->images = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
	}

Jedoch bekomme ich so einen SQL Fehler von TYPO3 mitgeteilt.

Wie verwendet mal FAL korrekt über Extbase?

MajPay ·

Wie kann es sein, dass man keine konkreten Beispiele und NICHTS dazu finden kann? Keine vernüfntige Testextension (blog_example kannst mittlerweile vergessen), die die gängigsten Szenarien abdeckt und keine Erkärungen.

Wie verwende ich FAL Referenzen in Extbase Models? Muss ich mir hierfür eklige Viewhelper bauen?

TYPO3 wird für mich immer mehr zur unüberschaubaren Katastrophe.

Stargast ·

Ja, da kann ich dir nur zustimmen! Katastrophe!

Ich hab den Plan verworfen meine Extension auf FAL aufzubauen - insbesondere weil FAL in Extbase noch als "experimental" gekennzeichnet ist. Finds schon etwas schade, dass sich da mittlerweile (knapp 2 Monate später) noch immer NICHTS getan hat. Obwohl FAL ein lange hinfälliger Schritt in die richtige Richtung ist, mit dem dämlichen bisherigen "File-Verwaltungs-System" von TYPO3 aufzuräumen, scheint es in der Extbase-Entwickler-Szene wohl bisher nicht angenommen zu werden - was die Resonanz auf diese Frage klar verdeutlicht.

Also mir persönlich bleibt mittlerweile nur noch die Hoffnung auf TYPO3 Neos... ansonsten wär ich vom TYPO3-Zug längst abgesprungen.
Neos (und Flow) verfolgen derzeit wirklich gute Ansätze - hoffentlich bleibts dabei! 🙂

MajPay ·

Ich versuche einfach das Filerepository in meinen Controller zu hängen und über die Methode findByRelation alle Files raus zu bekommen.

Muss doch irgendwie gehen.

MajPay ·

Das habe ich nun soweit mal hinbekommen (obwohl ich ganz stark vermute, dass man das auf keinen Fall so machen sollte).

Im Model habe ich aus der images property einfach ein array gemacht, habe keine types für set und get definiert und im Controller das fileRepository als dependencyInjection eingefügt.

Ich hole mir dann aus meinem Repository all meine Objekte und rufe dann eine Methode in meinem Controller auf, die die einzelnen Objekte um die Files erweitert.

Jedoch bekomme ich einen Update-Error im Frontend und habe keine Ahnung warum.
Hier sollte doch kein update passieren!?

Ich werd mir das weiter ansehen. Bin zwar kein Profi aber die Enttäuschung über Typo3 6.0 ist mittlerweile sehr groß. Wenns Neos nicht besser macht wirds das wohl bald gewesen sein für mich.

MajPay ·

Also, Extbase sieht anhand der Cleanproperties, dass das Model geändert wurde und will die Änderungen persistent machen. Um das zu verhindern markiert man die Property im Model mit einem vorangestellten _, aus images wird also _images.

Dann aus dem ObjectStorage ein simples array und die Setter, Getter anpassen.

Im Controller hängt man nun das FileRepository ein und erweitert seine Results manuell um die FileReferences. Nun hat man ein vollständiges Model samt FileReferences.

Wahrscheinlich muss ich noch einen ViewHelper schreiben, der mir aus meiner FileReference die URL und Metainformation extrahiert aber das ist dann das kleinste Problem.

Auf diese Weise braucht man, wenn FAL mal voll in Extbase unterstützt wird, nicht viel in seinen Models umschreiben.

Hier ein Snippet. Ist zwar sehr starr auf meine Datenstruktur abgestimmt aber man kann das wohl recht einfach in einen Service umschreiben, dem man table- und fieldnames als Parameter mitgibt.

/**
	 * show a list of specific regional objects
	 */
	public function listAction() {
		$objectList = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',',$this->settings['objects']);
		$objects = $this->regionalObjectRepository->findByUidList($objectList)->toArray();
		$this->addImagesToRegionalObjects($objects,1);
		$this->view->assign('objects',$objects);
	}
	
	/**
	 * Load Images from filerepository and add them to a regional object
	 * 
	 * @param \Pixelpoint\RegionalObject\Domain\Model\RegionalObject $regionalObject
	 * @param type $limit Limit for query
	 */
	public function loadImagesOfRegionalObject (\Pixelpoint\RegionalObject\Domain\Model\RegionalObject &$regionalObject, $limit=FALSE) {
		$images = $this->fileRepository->findByRelation('tx_regionalobject_domain_model_regionalobject', 'images', $regionalObject->getUid());
		$limit = ($limit !== FALSE && is_numeric($limit)) ? $limit : FALSE;
		$i = 0;
		foreach ($images as $image) {
			if ($limit && $i++ >= $limit) break;
			$regionalObject->addImage($image);
		}
	}
	
	/**
	 * Add images to regional objects
	 * 
	 * @param array $regionalObjects Array holding the regional objects
	 * @param type $limit limit for query
	 */
	public function addImagesToRegionalObjects (array &$regionalObjects, $limit=FALSE) {
		if (count($regionalObjects > 0)) {
			foreach ($regionalObjects as $regionalObject) {
				$this->loadImagesOfRegionalObject($regionalObject,$limit);
			}
		}
	}

Leider hat die findByRelation Methode des Filerepositories keinen Limitparameter, die Limiteinstellung ist also reine Ergebniskorrektur.

Das ganze kann man sicher noch stark verbessern, für meinen Zweck reichts aber vorerst mal.

MajPay ·

Nur kann ich nun nicht in Fluid auf die property _images zugreifen.

Sagt mal, soll das eine mieße Verarschung sein??!?

Ich habe wirlich keine Zeit mich mit der fehlenden Implementierung von Core-Features herumzuschlagen.

Weiß wer, wie ich in Fluid auf eine solche Property zugreifen kann? Oder brauch ich auch hierfür einen Viewhelper?

Oder kann ich eine Property nach dem überschreiben im Controller als clean kennzeichnen?

Gibts irgendeine elegante Lösung für dieses Problem?
Und ab wann kann man damit rechnen, dass Core-Features voll vom eigenen System unterstützt werden?

MajPay ·

Okay, um auf die Property vom Model zu zugreifen wird logischerweise die entsprechende get-Methode verwendet. Ich kann also eine getImages Methode implementieren, die _images liefert.

MajPay ·

Eine Referenz auf einen Folder ist ein sys_file_storage, eine Referenz auf eine Datei ist ein sys_file_reference datensatz

Man kann aber noch nicht ein objectStorage mit FileReferences befüllen lassen, das funtioniert noch nicht. Ich habe ein Array als nicht persistente property in meinem Model, das ich von meinem Controller aus mit sys_file anhand der sys_file_references Datensätze befülle. So funktioniert das bei mir.

sunixzs ·

Hi,

dazu mein Beispiel in Typo3 6.0.2. Wie MajPay erwähnt, nicht persistent nur als Getter:

TCA:

'image' => array(
	'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.images',
	'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('image', array(
		'appearance' => array(
			'createNewRelationLinkTitle' => 'LLL:EXT:cms/locallang_ttc.xlf:images.addFileReference'
		),
		'foreign_types' => array(
			\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => array(
				'showitem' => '
					--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
					--palette--;;filePalette'
			),
		)
	), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'])
),

Model:

class MyModel extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
	/**
	 * @var \TYPO3\CMS\Core\Resource\FileRepository
	 * @inject
	 */
	protected $typo3FALRepository;

	/**
	 * _image
	 *
	 * @var \array
	 */
	protected $_image;
	
	/**
	 * Returns the image
	 *
	 * @return \array<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $image
	 */
	public function getImage() {
	  if (count($this->_image)) {
	    return $this->_image;
	  }
	  $images = $this->typo3FALRepository->findByRelation("tx_extensionkey_domain_model_mymodel", "image", ($this->_localizedUid) ? $this->_localizedUid : $this->getUid());
	  if ($images) {
	    foreach ($images as $imageObject) {
	      try {
	        $this->_image[] = $imageObject->toArray();
	      } catch (Exception $e) {
	        // it is possible the url is moved or removed 
	      }
	    }
	  }
	  return $this->_image;
	}
}

Hier ist darauf zu achten, dass findByRelation() die lokalisierte UID des Models erwartet, um auch die lokalisierte fileRelation zu bekommen.

Parameter im fileRelation wie url, title, alternative werden mit toArray() gesetzt und stehen dann im View zur Verfügung.

View:

{namespace tx = VENDOR\Extension\ViewHelpers}
<f:for each="{mymodel.image}" as="image">
	<div class="image">
		<f:if condition="{image.link}">
			<f:then>
				<tx:typolink parameter="{image.link}"><f:image src="{image.url}" alt="{image.alternative}" title="{image.title}" width="200" /></tx:typolink>
			</f:then>
			<f:else>
				<f:image src="{image.url}" alt="{image.alternative}" title="{image.title}" width="200" />
			</f:else>
		</f:if>
	</div>
</f:for>

Der TypolinkViewHelper ist eine superfeine Sache, die ich hier fand:
https://github.com/castiron/cicbase/blob/master/Classes/ViewHelpers/TypolinkViewHelper.php

Edith sagt: Im ViewHelper hat der Namespace Einzug gehalten. Demnach muss es wie folgt aussehen:

<?php
namespace VENDOR\ExtensionKey\ViewHelpers;
/*                                                                        *
 * This script belongs to the FLOW3 package "Fluid".                      *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU Lesser General Public License as published by the *
 * Free Software Foundation, either version 3 of the License, or (at your *
 * option) any later version.                                             *
 *                                                                        *
 * This script is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
 * General Public License for more details.                               *
 *                                                                        *
 * You should have received a copy of the GNU Lesser General Public       *
 * License along with the script.                                         *
 * If not, see http://www.gnu.org/licenses/lgpl.html                      *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

/**
 *	Wraps some of the basic Typolink settings in a viewhelper. Good for rendering links to pages and page titles
 *	when all you have is the page id.
 */
class TypolinkViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
	/**
	 * @param string $parameter
	 * @param string $target
	 * @param int $noCache
	 * @param int $useCacheHash
	 * @param array $additionalParams
	 * @param string $ATagParams
	 * @return mixed
	 */
	public function render($parameter, $target='',$noCache=0,$useCacheHash=1,$additionalParams=array(),$ATagParams = '') {
		$typoLinkConf = array(
			'parameter' => $parameter,
		);

		if($target) {
			$typoLinkConf['target'] = $target;
		}

		if($noCache) {
			$typoLinkConf['no_cache'] = 1;
		}

		if($useCacheHash) {
			$typoLinkConf['useCacheHash'] = 1;
		}

		if(count($additionalParams)) {
			$typoLinkConf['additionalParams'] = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('',$additionalParams);
		}

		if(strlen($ATagParams)) {
			$typoLinkConf['ATagParams'] = $ATagParams;
		}

		$linkText = $this->renderChildren();

		$textContentConf = array(
			'typolink.' => $typoLinkConf,
			'value' => $linkText
		);

		return $GLOBALS['TSFE']->cObj->cObjGetSingle('TEXT',$textContentConf);
	}
}
?>

LG sun