Extbase - Objekte handeln: Unterschied zwischen den Versionen
| (7 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
| + | == Links == | ||
| + | [[Extbase Extensions - Snippets und Glossar]] | ||
| + | |||
| + | https://typo3.org/api/typo3cms/class_t_y_p_o3_1_1_c_m_s_1_1_extbase_1_1_persistence_1_1_object_storage.html | ||
| + | |||
| + | Zu m:n Verbindungen allgemenin: http://blog.undkonsorten.com/datenbankrelationen-typo3-irre-extension | ||
| + | |||
| + | == Objekte abfragen == | ||
| + | === In m:n Verbindung === | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $author->getBook()->rewind(); | ||
| + | $author->getBook()->current()->getTitle(); | ||
| + | // or example with some more functionality | ||
| + | private function getDeviceClassUidFromRma($rma){ | ||
| + | if(count($rma->getMetadevice())){ | ||
| + | $myDevice = $rma->getMetadevice(); | ||
| + | $myDevice->rewind(); | ||
| + | $deviceUid = $myDevice->current()->getDevice()->getDeviceClass()->getUid(); | ||
| + | return $deviceUid; | ||
| + | }else return false; | ||
| + | } | ||
| + | </syntaxhighlight> | ||
== Objekte erstellen == | == Objekte erstellen == | ||
Wenn das Repository im Controller injected wurde: | Wenn das Repository im Controller injected wurde: | ||
| Zeile 4: | Zeile 26: | ||
$this->redirect('list'); | $this->redirect('list'); | ||
== Kindobjekte erstellen == | == Kindobjekte erstellen == | ||
| − | Hier kann man nicht einfach erstellen sonst ist die Datenbankverbindung nicht vorhanden. Also muß man vorher im View das Mutterobjekt durchschleifen und danach im Controller die Verknüpfung berücksichtigen: | + | Hier kann man nicht einfach erstellen sonst ist die Datenbankverbindung zum Elternobjekt nicht vorhanden. Also muß man vorher im View das Mutterobjekt durchschleifen und danach im Controller die Verknüpfung berücksichtigen: |
'''Controller''' | '''Controller''' | ||
| Zeile 41: | Zeile 63: | ||
$this->objectManager->get( 'Lobacher\\Simpleblog\\Domain\\Repository\\BlogRepository' )->update($blog); | $this->objectManager->get( 'Lobacher\\Simpleblog\\Domain\\Repository\\BlogRepository' )->update($blog); | ||
$this->redirect('show','Blog',NULL,array('blog'=>$blog)); | $this->redirect('show','Blog',NULL,array('blog'=>$blog)); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == Objekte löschen == | ||
| + | === Kindobjekte in m:n Beziehungen löschen=== | ||
| + | Über die Annotation @cascade remove im Model werden nur die Beziehungen gelöscht nicht die Kindobjekte. Sollen diese ebenfalls gelöscht werden geht das so: | ||
| + | http://www.typo3.net/forum/thematik/zeige/thema/117172/ | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $company = $this->companyRepository->findByUid(5); | ||
| + | $members = $company->getMembers(); | ||
| + | $memberClone = clone $members; | ||
| + | $members->removeAll($memberClone); | ||
| + | $this->companyRepository->update($company); | ||
| + | $this->companyRepository->remove($company); | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == Manuell persistieren == | ||
| + | Normalerweise wird nach Ende einer Action automatisch persistiert. Will man das schon vorher erreichen (um z.b. in der gleichen Action die Änderungen noch anzuzeigen oder wenn man gleich zu einer Detailansicht Action weiterleiten will (dann braucht man die uid) kann man das so machen: | ||
| + | http://stackoverflow.com/questions/19588474/typo3-extbase-get-uid-of-non-persisted-object | ||
| + | |||
| + | <syntaxhighlight lang="php"> | ||
| + | /** | ||
| + | * persistence manager | ||
| + | * | ||
| + | * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface | ||
| + | * @inject | ||
| + | */ | ||
| + | protected $persistenceManager; | ||
| + | |||
| + | // ... | ||
| + | |||
| + | $this->persistenceManager->persistAll(); | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == Objekte kopieren == | ||
| + | Objekte wie im Backend mit allen Kindobjekten kopieren ist im Frontend sehr mühselig. Einfacher geht es mit einem simulierten Backenduser. Dieser wird im Backend angelegt. Dazu wird eine Serviceklasse angelegt über die man den User als Datahandler (so heißt er auch im Beispiel) nutzen kann. | ||
| + | |||
| + | http://blog.marcdesign.ch/2015/05/27/typo3-extbase-objekte-kopieren/ | ||
| + | |||
| + | Mit folgender Serviceklasse könnt Ihr euch einen Backenduser simulieren und somit den “\TYPO3\CMS\Core\DataHandling\DataHandler” von TYPO3 nutzen um einwandfreie kopien ohne Einschränkungen eurer Objekte zu erstellen. | ||
| + | |||
| + | <syntaxhighlight lang="php"> | ||
| + | /** | ||
| + | * @param \VENDOR\Extname\Domain\Model\Page $page | ||
| + | * @return void | ||
| + | */ | ||
| + | public function copyAction(\VENDOR\Extname\Domain\Model\Page $page) { | ||
| + | /** | ||
| + | * @var \VENDOR\Extname\Service\DataHandler $dataHandler | ||
| + | */ | ||
| + | $dataHandler = $this->objectManager->get('VENDOR\\Extname\\Service\\DataHandler'); | ||
| + | $newUid = $dataHandler->copyRecord($page); | ||
| + | //Nur notwendig wenn ihr z.b. den Titel nachträglich ändern wollt. | ||
| + | $newObject = $this->pageRepository->findByUid($newUid); | ||
| + | $newObject->setTitle(sprintf('KOPIE(%1$s):',date('d.m.y-H:i:s')).$newObject->getTitle()); | ||
| + | $newObject->setHidden(true); | ||
| + | $this->pageRepository->update($newObject); | ||
| + | $this->redirect('edit', null, null, array('page' => $newObject)); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | Und so sieht die neue Serviceklasse aus: | ||
| + | Nicht vergessen im Backend einen Admin Benutzer namens “datahandler” anzulegen oder was euch sonst einfällt. | ||
| + | <syntaxhighlight lang="php"> | ||
| + | <?php | ||
| + | namespace VENDOR\Extname\Service; | ||
| + | /*************************************************************** | ||
| + | * Copyright notice | ||
| + | * | ||
| + | * (c) 2015 Marc Gutknecht | ||
| + | * | ||
| + | * 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! | ||
| + | ***************************************************************/ | ||
| + | |||
| + | use TYPO3\CMS\Core\Utility\GeneralUtility; | ||
| + | use TYPO3\CMS\Extbase\Utility\DebuggerUtility; | ||
| + | |||
| + | class DataHandler extends \TYPO3\CMS\Core\DataHandling\DataHandler { | ||
| + | |||
| + | /** | ||
| + | * __construct | ||
| + | */ | ||
| + | public function __construct() { | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Simulate Backend User for DataHandler | ||
| + | */ | ||
| + | public function simulateBackendUser() { | ||
| + | /** @var \TYPO3\CMS\Backend\FrontendBackendUserAuthentication $BE_USER */ | ||
| + | $BE_USER = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\FrontendBackendUserAuthentication'); | ||
| + | $BE_USER->setBeUserByName('datahandler'); | ||
| + | if ($BE_USER->user['uid']) { | ||
| + | $BE_USER->fetchGroupData(); | ||
| + | } | ||
| + | $BE_USER->uc_default['copyLevels']= '9999'; | ||
| + | $BE_USER->uc = $BE_USER->uc_default; | ||
| + | $GLOBALS['PAGES_TYPES'][254]['allowedTables'] = '*'; | ||
| + | return $BE_USER; | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Copying a single record | ||
| + | * | ||
| + | * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $value | ||
| + | * @param boolean $first Is a flag set, if the record copied is NOT a 'slave' to another record copied. That is, if this record was asked to be copied in the cmd-array | ||
| + | * @param array $overrideValues Associative array with field/value pairs to override directly. Notice; Fields must exist in the table record and NOT be among excluded fields! | ||
| + | * @param string $excludeFields Commalist of fields to exclude from the copy process (might get default values) | ||
| + | * @param integer $language Language ID (from sys_language table) | ||
| + | * @return integer ID of new record, if any | ||
| + | */ | ||
| + | public function copyRecord($object, $first = 0, $overrideValues = array(), $excludeFields = '', $language = 0) { | ||
| + | if($object instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface){ | ||
| + | $this->BE_USER = $this->simulateBackendUser(); | ||
| + | $this->userid = $this->BE_USER->user['uid']; | ||
| + | $this->username = $this->BE_USER->user['username']; | ||
| + | $this->admin = true; | ||
| + | |||
| + | if (!is_object($GLOBALS['LANG'])) { | ||
| + | $GLOBALS['LANG'] = GeneralUtility::makeInstance('\\TYPO3\\CMS\\Lang\\LanguageService'); | ||
| + | $GLOBALS['LANG']->csConvObj = GeneralUtility::makeInstance('\\TYPO3\\CMS\\Core\\Charset\\CharsetConverter'); | ||
| + | } | ||
| + | |||
| + | return parent::copyRecord(MyUtility::resolveTableName($object), $object->getUid(), $object->getPid(), 1, $overrideValues = array(), $excludeFields = '', $language = 0); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | ?> | ||
| + | </syntaxhighlight> | ||
| + | Die Funktion resolveTableName ist bei mir eine von vielen statischen Funktionen (Quelle:/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapFactory.php) und sieht wie folgt aus: | ||
| + | <syntaxhighlight lang="php"> | ||
| + | /** | ||
| + | * Resolve the table name for the given class name | ||
| + | * | ||
| + | * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $domainObject | ||
| + | * @return string The table name | ||
| + | */ | ||
| + | public static function resolveTableName(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $domainObject) { | ||
| + | $className = get_class($domainObject); | ||
| + | if (strpos($className, '\\') !== FALSE) { | ||
| + | $classNameParts = explode('\\', $className, 6); | ||
| + | // Skip vendor and product name for core classes | ||
| + | if (strpos($className, 'TYPO3\\CMS\\') === 0) { | ||
| + | $classPartsToSkip = 2; | ||
| + | } else { | ||
| + | $classPartsToSkip = 1; | ||
| + | } | ||
| + | $tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip))); | ||
| + | } else { | ||
| + | $tableName = strtolower($className); | ||
| + | } | ||
| + | return $tableName; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Aktuelle Version vom 30. Juli 2015, 13:10 Uhr
Links[Bearbeiten]
Extbase Extensions - Snippets und Glossar
Zu m:n Verbindungen allgemenin: http://blog.undkonsorten.com/datenbankrelationen-typo3-irre-extension
Objekte abfragen[Bearbeiten]
In m:n Verbindung[Bearbeiten]
$author->getBook()->rewind();
$author->getBook()->current()->getTitle();
// or example with some more functionality
private function getDeviceClassUidFromRma($rma){
if(count($rma->getMetadevice())){
$myDevice = $rma->getMetadevice();
$myDevice->rewind();
$deviceUid = $myDevice->current()->getDevice()->getDeviceClass()->getUid();
return $deviceUid;
}else return false;
}
Objekte erstellen[Bearbeiten]
Wenn das Repository im Controller injected wurde:
$this->miniObjectRepository->add($newMiniObject);
$this->redirect('list');
Kindobjekte erstellen[Bearbeiten]
Hier kann man nicht einfach erstellen sonst ist die Datenbankverbindung zum Elternobjekt nicht vorhanden. Also muß man vorher im View das Mutterobjekt durchschleifen und danach im Controller die Verknüpfung berücksichtigen:
Controller
/**
* addForm action - displays a form for adding a post
*
* @param \Lobacher\Simpleblog\Domain\Model\Blog $blog
* @param \Lobacher\Simpleblog\Domain\Model\Post $post
*/
public function addFormAction(
\Lobacher\Simpleblog\Domain\Model\Blog $blog,
\Lobacher\Simpleblog\Domain\Model\Post $post = NULL) {
$this->view->assign('blog',$blog);
$this->view->assign('post',$post);
}
--> Fluid
<f:form action="{action}" object="{post}" name="post" arguments="{blog:blog}" additionalAttributes="{role:'form'}">
--> Controller Wenn man nicht injekten will wie in dem Beispiel muß man über den objectManager gehen um das Elternobjekt (hier den Blog) zu holen.
/**
* add action - adds a post to the repository
*
* @param \Lobacher\Simpleblog\Domain\Model\Blog $blog
* @param \Lobacher\Simpleblog\Domain\Model\Post $post
*/
public function addAction(
\Lobacher\Simpleblog\Domain\Model\Blog $blog,
\Lobacher\Simpleblog\Domain\Model\Post $post) {
$post->setPostdate(new \DateTime());
//$this->postRepository->add($post);
$blog->addPost($post);
$this->objectManager->get( 'Lobacher\\Simpleblog\\Domain\\Repository\\BlogRepository' )->update($blog);
$this->redirect('show','Blog',NULL,array('blog'=>$blog));
}
Objekte löschen[Bearbeiten]
Kindobjekte in m:n Beziehungen löschen[Bearbeiten]
Über die Annotation @cascade remove im Model werden nur die Beziehungen gelöscht nicht die Kindobjekte. Sollen diese ebenfalls gelöscht werden geht das so: http://www.typo3.net/forum/thematik/zeige/thema/117172/
$company = $this->companyRepository->findByUid(5);
$members = $company->getMembers();
$memberClone = clone $members;
$members->removeAll($memberClone);
$this->companyRepository->update($company);
$this->companyRepository->remove($company);
Manuell persistieren[Bearbeiten]
Normalerweise wird nach Ende einer Action automatisch persistiert. Will man das schon vorher erreichen (um z.b. in der gleichen Action die Änderungen noch anzuzeigen oder wenn man gleich zu einer Detailansicht Action weiterleiten will (dann braucht man die uid) kann man das so machen: http://stackoverflow.com/questions/19588474/typo3-extbase-get-uid-of-non-persisted-object
/**
* persistence manager
*
* @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
* @inject
*/
protected $persistenceManager;
// ...
$this->persistenceManager->persistAll();
Objekte kopieren[Bearbeiten]
Objekte wie im Backend mit allen Kindobjekten kopieren ist im Frontend sehr mühselig. Einfacher geht es mit einem simulierten Backenduser. Dieser wird im Backend angelegt. Dazu wird eine Serviceklasse angelegt über die man den User als Datahandler (so heißt er auch im Beispiel) nutzen kann.
http://blog.marcdesign.ch/2015/05/27/typo3-extbase-objekte-kopieren/
Mit folgender Serviceklasse könnt Ihr euch einen Backenduser simulieren und somit den “\TYPO3\CMS\Core\DataHandling\DataHandler” von TYPO3 nutzen um einwandfreie kopien ohne Einschränkungen eurer Objekte zu erstellen.
/**
* @param \VENDOR\Extname\Domain\Model\Page $page
* @return void
*/
public function copyAction(\VENDOR\Extname\Domain\Model\Page $page) {
/**
* @var \VENDOR\Extname\Service\DataHandler $dataHandler
*/
$dataHandler = $this->objectManager->get('VENDOR\\Extname\\Service\\DataHandler');
$newUid = $dataHandler->copyRecord($page);
//Nur notwendig wenn ihr z.b. den Titel nachträglich ändern wollt.
$newObject = $this->pageRepository->findByUid($newUid);
$newObject->setTitle(sprintf('KOPIE(%1$s):',date('d.m.y-H:i:s')).$newObject->getTitle());
$newObject->setHidden(true);
$this->pageRepository->update($newObject);
$this->redirect('edit', null, null, array('page' => $newObject));
}
Und so sieht die neue Serviceklasse aus: Nicht vergessen im Backend einen Admin Benutzer namens “datahandler” anzulegen oder was euch sonst einfällt.
<?php
namespace VENDOR\Extname\Service;
/***************************************************************
* Copyright notice
*
* (c) 2015 Marc Gutknecht
*
* 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!
***************************************************************/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
class DataHandler extends \TYPO3\CMS\Core\DataHandling\DataHandler {
/**
* __construct
*/
public function __construct() {
}
/**
* Simulate Backend User for DataHandler
*/
public function simulateBackendUser() {
/** @var \TYPO3\CMS\Backend\FrontendBackendUserAuthentication $BE_USER */
$BE_USER = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\FrontendBackendUserAuthentication');
$BE_USER->setBeUserByName('datahandler');
if ($BE_USER->user['uid']) {
$BE_USER->fetchGroupData();
}
$BE_USER->uc_default['copyLevels']= '9999';
$BE_USER->uc = $BE_USER->uc_default;
$GLOBALS['PAGES_TYPES'][254]['allowedTables'] = '*';
return $BE_USER;
}
/**
* Copying a single record
*
* @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $value
* @param boolean $first Is a flag set, if the record copied is NOT a 'slave' to another record copied. That is, if this record was asked to be copied in the cmd-array
* @param array $overrideValues Associative array with field/value pairs to override directly. Notice; Fields must exist in the table record and NOT be among excluded fields!
* @param string $excludeFields Commalist of fields to exclude from the copy process (might get default values)
* @param integer $language Language ID (from sys_language table)
* @return integer ID of new record, if any
*/
public function copyRecord($object, $first = 0, $overrideValues = array(), $excludeFields = '', $language = 0) {
if($object instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface){
$this->BE_USER = $this->simulateBackendUser();
$this->userid = $this->BE_USER->user['uid'];
$this->username = $this->BE_USER->user['username'];
$this->admin = true;
if (!is_object($GLOBALS['LANG'])) {
$GLOBALS['LANG'] = GeneralUtility::makeInstance('\\TYPO3\\CMS\\Lang\\LanguageService');
$GLOBALS['LANG']->csConvObj = GeneralUtility::makeInstance('\\TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
}
return parent::copyRecord(MyUtility::resolveTableName($object), $object->getUid(), $object->getPid(), 1, $overrideValues = array(), $excludeFields = '', $language = 0);
}
}
}
?>
Die Funktion resolveTableName ist bei mir eine von vielen statischen Funktionen (Quelle:/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapFactory.php) und sieht wie folgt aus:
/**
* Resolve the table name for the given class name
*
* @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $domainObject
* @return string The table name
*/
public static function resolveTableName(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $domainObject) {
$className = get_class($domainObject);
if (strpos($className, '\\') !== FALSE) {
$classNameParts = explode('\\', $className, 6);
// Skip vendor and product name for core classes
if (strpos($className, 'TYPO3\\CMS\\') === 0) {
$classPartsToSkip = 2;
} else {
$classPartsToSkip = 1;
}
$tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip)));
} else {
$tableName = strtolower($className);
}
return $tableName;
}