I found this Answer here on stackoverflow.
I need a Hook, which is executed when a page and content is created, deleted, moved or updated.
I only found this hook processDatamap_postProcessFieldArray but it will not be executed if the content is created, deleted, moved or updated. It is executed only when a page is created or deleted.
I'm on TYPO3 Version 7.6.9.
Is there a list of all available hooks?
Greetings.
Check out this answer. It has a detailed explanation on how to set up a hook that executes upon record deletion and will certainly help you out.
To sum it up, you need to register your hook in an ext_tables.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['YourHook'][] = 'YourVendor\\YourExt\\Hooks\\YourHook';
And declare the hook itself in:
/ext/your_ext/Classes/Hooks/yourHook.php
Here is a partial list of available hooks from the official Docs.
Edit
Your are looking for the correct Member Function.
To be honest, I am not sure if you need to hook multiple of them or if using processCmdmap_afterFinish will do what you need:
<?php
namespace YourVendor\YourExt\Hooks;
class ProcessCmdmap {
/**
* hook that is called when an element shall get deleted
*
* #param string $table the table of the record
* #param integer $id the ID of the record
* #param array $record The accordant database record
* #param boolean $recordWasDeleted can be set so that other hooks or
* #param DataHandler $tcemainObj reference to the main tcemain object
* #return void
*/
function processCmdmap_postProcess($command, $table, $id, $value, $dataHandler) {
/* Does this trigger at all for the actions you need? */
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($command);
die();
if ($command == 'delete' ||
$command == 'update' ||
$command == 'move' ||
$table == 'tx_yourext_domain_model_something') {
}
}
}
large portions of this code come from this answer
Related
Hi have a backend module extension to upload files. Im using helhum fileupload for reference. File upload is successful. But the file filed of table updates the uid of sys_file_reference instead of no of files. Why it happens?
<f:form.upload property="file" />
my reference is this Where can I set the table name and no_files in my table and sys_file reference
The property "file" I assume is an 1:1 relation which is why the UID of the file reference is what gets written in to the field.
Had the property been a M:N or 1:N table you would see the number of files, as you expect - and Extbase would need to know you want an ObjectStorage containing FileReference objects on your property.
Regarding the subject, if your Repository returns NULL when you do findAll, this is almost always because of storage page restrictions. To overcome it, override either createQuery and manipulate QuerySettings on the query before it gets returned, setting respectStoragePageUids(false).
I got the solution for my problem. my model was
/**
* Sets the file
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $file
* #return void
*/
public function setFile(\TYPO3\CMS\Extbase\Domain\Model\FileReference $file = NULL)
{
$this->file = $file;
}
I removed the type from argument list .Now its working fine.My updated code is below
/**
* Sets the file
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $file
* #return void
*/
public function setFile($file = NULL)
{
$this->file = $file;
}
I would like to build a preview page for a create form. I set "deleted" property of the record to "1" when in previewAction because in the BE the list module is used to approve the inserted records - so if the record was never finally saved its deleted anyway.
Problem: I can create the record (deleted=1) - I can jump back to the form (no history back for I have to keep the created object). But if I submit again the property mapping tells me
Object of type MyModel with identity "3" not found.
Of course that's because its deleted. The settings in the Repository to ignore deleted are not taking action here.
Yes I could bypass the Extbase magic by filling up everything manually, but this is not what I want.
Here is the action to get an idea what I'm trying
/**
* action preview
*
* #param MyModel
* #return void
*/
public function previewAction(MyModel $newModel)
{
//check if model was already saved
$uid = $this->request->hasArgument('uid') ? this->request->getArgument('uid') : 0;
if($uid){
$newModel = $this->myRepository->findDeletedByUid($uid);
$this->myRepository->update($newModel);
}
else{
$newModel->setDeleted(true);
$this->myRepository->add($newModel);
}
$this->view->assign('ad', $newModel);
$this->persistenceManager->persistAll();
$uid = $this->persistenceManager->getIdentifierByObject($newModel);
$this->view->assign('uid', $uid);
}
Any ideas?
The Extbase default query settings suppress deleted objects.
Since you've already stated the custom query findDeletedByUid() in your repository, you just need to set it to include deleted records. It is important, however, that if you want to call your controller action using the object, you'll have to retrieve it before calling the action. Use an initialization action for that. The initializaton will be called automatically before the action.
If you want to set wether the object is deleted, you'll also going to need to define a property, getter and setter in your Domain Model and a proper definition in your tca to enable the data mapper to access the column.
In the repository:
public function findDeletedByUid($uid) {
$query = $this->createQuery();
$query->getQuerySettings()->setIncludeDeleted(true);
$query->matching(
$query->equals('uid',$uid)
);
return $query->execute();
}
In your Controller class:
/**
* initialize action previewAction
* Overrides the default initializeAction with one that can retrieve deleted objects
*/
public function initializePreviewAction(){
if( $this->request->hasArgument('mymodel') ){
$uid = $this->request->getArgument('mymodel');
if( $mymodel = $this->mymodelRepository->findDeletedByUid($uid) ){
$this->request->setArgument($mymodel);
} else {
// handle non retrievable object here
}
} else {
// handle missing argument here
}
}
In your Domain Model:
...
/**
* #var bool
*/
protected $deleted;
/**
* #return bool
*/
public function getDeleted() {
return $this->deleted;
}
/**
* #param bool $deleted
*/
public function setDeleted($deleted) {
$this->deleted = $deleted;
}
In your tca.php
...
'deleted' => array(
'exclude' => 1,
'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.deleted',
'config' => array(
'type' => 'check',
),
),
Instead of doing any magic with deleted, you should use the hidden field to allow editors to preview documents.
You can tell your query to include hidden records inside the repository.
Your findDeletedByUid($uid) function caught my eye. If it's not a custom function, should it use something like findByDeleted(TRUE) or findByDeleted(1) in combination with ->getFirst() or ->findByUid()? You can find discussions in the Extbase manual reference and the Repository __call() function API sections.
Thanks for all hints.
I think depending to the answers its not possible without bypass extbase property-mapping magic. So I think in general its not a good idea to do it like that.
So I put now my own flag "stored" to the model.
In BE List-Module the not "stored" objects are still visible, but using an own BE Module or deleting the not "stored" object by a cron-job should do the job.
If anyone has a bedder idea feel free to share it :-)
I would like to execute some individual code when one of my Extbase domain objects is deleted from the list view in TYPO3 backend.
Thought that it could / would work by overwriting the remove( $o ) method in the according repository like
public function remove( $object ) {
parent::__remove( $object );
do_something_i_want();
}
, but that won't work I guess. Looks like the repository-methods are only called / used by actions of my extension (e.g. if I had some delete-action in a FE- or BE-plugin) but not when the object is just deleted from list view in the backend? I don't use (up to now) any FE/BE-plugin / -actions - only the simple add/edit/delete functions in the backends list view of my storage folder.
Background: I have e.g. two models with some 1:n relation (let's say singer and song), where one object includes some uploaded file (album_cover > pointing to the file's URL in /uploads/myext/ folder); using #cascade works fine for deleting every song belonging to a singer that is deleted, but it won't touch the file uploaded (only) for song.album_cover - leading to quite some waste over time. So I would love to do some sort of onDeletionOfSinger() { deleteAllFilesForHisSongs(); }-thing.
(Same thing would apply on deletion of let's say a single song and it's album_cover-file.)
Sounds quite easy & common, but I just don't get behind it and found nothing useful - would love some hint / pointing to the right direction :-).
List view uses TCEmain hooks during its operations, so you can use one of them to intersect delete action, i.e.: processCmdmap_deleteAction
Register your hooks class in typo3conf/ext/your_ext/ext_tables.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'][] = 'VENDORNAME\\YourExt\\Hooks\\ProcessCmdmap';
Create a class with valid namespace and path (according to previous step)
file: typo3conf/ext/your_ext/Classes/Hooks/ProcessCmdmap.php
<?php
namespace VENDORNAME\YourExt\Hooks;
class ProcessCmdmap {
/**
* hook that is called when an element shall get deleted
*
* #param string $table the table of the record
* #param integer $id the ID of the record
* #param array $record The accordant database record
* #param boolean $recordWasDeleted can be set so that other hooks or
* #param DataHandler $tcemainObj reference to the main tcemain object
* #return void
*/
function processCmdmap_postProcess($command, $table, $id, $value, $dataHandler) {
if ($command == 'delete' && $table == 'tx_yourext_domain_model_something') {
// Perform something before real delete
// You don't need to delete the record here it will be deleted by CMD after the hook
}
}
}
Don't forget to clear system cache after registering new hook's class
In addition to biesiors answer I want to point out, that there is also a signalSlot for this. So you can rather register on that signal than hooking into tcemain.
in your ext_localconf.php put:
$signalSlotDispatcher =
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
$signalSlotDispatcher->connect(
'TYPO3\CMS\Extbase\Persistence\Generic\Backend',
'afterRemoveObject',
'Vendor\MxExtension\Slots\MyAfterRemoveObjectSlot',
'myAfterRemoveObjectMethod'
);
So in your Slot you have this PHP file:
namespace Vendor\MxExtension\Slots;
class MyAfterRemoveObjectSlot {
public function myAfterRemoveObjectMethod($object) {
// do something
}
}
Note thet $object will be the $object that was just removed from the DB.
For more information, see https://usetypo3.com/signals-and-hooks-in-typo3.html
I have created a after_relationship_add logic hook in cases module and in this module there is a custom field for one of the custom module relationship data to be inserted. The hook is called properly, and everything is working fine. but when I am updating the case record in hook logic, the update query is not working. But if I add a die(); statement after update query execution, the record gets updated. logic hook code is given below
public function updateData($bean, $event, $arguments){
$caseid = $bean->id;
$dataid = $arguments['related_id'];
$query = "SELECT name FROM data1_data where id = '" .$dataid. "'";
$dataresult = $GLOBALS['db']->query($query , false);
$dataname = "";
while (($row = $GLOBALS['db']->fetchByAssoc($dataresult )) != null) {
$dataname = $row['name'];
}
$newQuery = 'UPDATE cases_cstm SET data_c = "'.$dataname.'" where id_c = "'.$caseid.'" ';
$newResult = $GLOBALS['db']->query($newQuery);
/* here when die() statement is added update query executes properly and
* after removing die(); statement nothing happens.*/
die();
}
Can any one help me in this issues?
In SugarCRM, you should practically never interact with the database directly. Almost anything you'll need to do can be done with the SugarBean object and it's extensions. What you're seeing here is a great example of why: your update is hitting the database, but the rest of the SugarCRM update that loads immediately afterwards is wiping it out.
I've rewritten your function using SugarBean and BeanFactory. Notice how much less code is needed, and I expect you'll find that it works because it won't cause additional updates.
The one bit I'm not sure about is whether or not you really need the $bean->save(); at the end. If we were in a before_save logic hook it wouldn't be needed, but I use the after_relationship_add less frequently, so it might be necessary here.
/**
* #param $bean aCase object
* #param $event string, or specifically 'after_relationship_add'
* #param $arguments array
*/
public function updateData($bean, $event, $arguments){
/*
* Instead of loading the data1_data information from the database
* directly, consider using the SugarBean PHP object, as this is a SugarCRM
* best practice.
*
* Note that we return early if the data1_data object cannot be found or
* if the 'name' value is blank (as that would make the rest of this script
* useless)
*/
$data = BeanFactory::getBean('data1_data',$arguments['related_id']);
if(empty($data->name)) return;
$dataname = $data->name;
/*
* Instead of sending an update query directly to the database, use the
* SugarBean objects, one's loaded already in $bean. Saving objects
* with the SugarBean objects instead of direct SQL will ensure that
* all workflows and logic hooks are executed correctly. Further,
* updating with direct SQL *before* a pending update is sent (such as
* in a logic hook) will likely overwrite whatever update we're making
* in SQL.
*/
$bean->data_c = $dataname;
$bean->save();
}
I want do give the function to 'restore' deleted Object in my FE-Ext. It seems, that it does not find any deleted records an so i cannot update them set deleted = 0.
What you be you sugestion to handle that from the controller?:
$query->getQuerySettings()->setIgnoreEnableFields(TRUE);
$query->getQuerySettings()->setIncludeDeleted(TRUE);
Thank you.
Im not quite sure what you mean by "from the controller". Normally you implement this in your repository and just call the method from the controller.
In your repo:
public function findRecordEvenIfItIsDeleted($uid) {
$query = $this->createQuery();
$settings = $query->getQuerySettings();
settings->setIgnoreEnableFields(TRUE);
settings->setIncludeDeleted(TRUE);
$query->matching($query->equals('uid', $uid));
return $query->execute();
}
In your controller:
$myObject = $this->myRepsository->findRecordEvenIfItIsDeleted($uid);
Done. (Of course your storage pid must be set (or disable respectStoragePage as well)
You're adding does not throw any error because you are setting the querySettings to include deleted records. But maybe, this setting has to be enabled even when you are updating, as the repository should find the object you are updating.
I haven't tested it but give this a try.
In your repository(just a pseudo code)
public function update($modifiedObject) {
settings->setIncludeDeleted(TRUE);
parent::update($modifiedObject);
}
I know this question was asked long time ago but today i had a similar problem with a hidden object. My solution was this one:
add this to your Model (in your case exchange "hidden" by "deleted"):
/**
* #var boolean
*/
protected $hidden;
/**
* #return boolean $hidden
*/
public function getHidden() {
return $this->hidden;
}
/**
* #return boolean $hidden
*/
public function isHidden() {
return $this->getHidden();
}
/**
* #param boolean $hidden
* #return void
*/
public function setHidden($hidden) {
$this->hidden = $hidden;
}
in your repository add this function to find the deleted/hidden object:
public function findHiddenByUid($uid) {
$query = $this->createQuery();
$query->getQuerySettings()->setIgnoreEnableFields(TRUE);
$query->getQuerySettings()->setEnableFieldsToBeIgnored(array('disabled','hidden'));
return $query
->matching($query->equals('uid', $uid))
->execute()
->getFirst();
}
now in your Controller you can read the object, set the "hidden" option and update it:
$yourobject = $this->yourobjectRepository->findHiddenByUid($uid);
$yourobject->setHidden(1);
$this->yourobjectRepository->update($yourobject);
Maybe not interesting for your task but for others:
In my case i additionally had the problem posting a hidden object in a form to an action. So note that if you want to post an object by a form, it is better (or probably necessary) to first set the objects deleted/hidden option to 0.