Update object in hook - typo3

I'm using a hook after the user unhide a record. In this hook i want to update a object.
class ProcessCmdmap {
function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$reference) {
if ($table == 'tx_oaevents_domain_model_events' && $status == 'update' && $fieldArray['hidden'] == 0) {
// Get objectmanager
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
// Get repo
$repository = $objectManager->get('Mab\\Oaevents\\Domain\\Repository\\EventsRepository');
// Get config manager
$configurationManager = $objectManager->get('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
// Get settings and storage pid
$settings = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
$storagePid = $settings['plugin.']['tx_oaevents.']['persistence.']['storagePid'];
// Build default query settings
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setStoragePageIds(array($storagePid));
$repository->setDefaultQuerySettings($querySettings);
$object = $repository->findByUid($id);
// modify object
// Update / Persist object
}
}
}
But i can't retrieve a object with "findByUid()" or "findAll()". Do i use the objectmanager in wrong scope? Or how can retrieve and update into hooks my object?
Can someone give me a hint?
Update:
Now i give up :( and not use the objectmanager and repository, i use the functions from $GLOBALS['TYPO3_DB']

I definitely recommend to follow your solution by using $GLOBALS['TYPO3_DB'] at this point. Extbase just brings in a lot of overhead here.
Without Extbase you also need less code here.
Anyway:
Most likely the generated queries by Extbase are broken. Log your queries and check the generated one. Try it out and modify it, until it works. Check the difference.

You can try without using "setStoragePageIds".
If you are looking record by uid it is useless.
My working code for processDatamap:
/** #var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager */
$objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
/** #var $orderRepository \Vendor\ExtensionName\Domain\Repository\OrderRepository */
$orderRepository = $objectManager->get('Vendor\\ExtensionName\\Domain\\Repository\\OrderRepository');
$order = $orderRepository->findByUid($id);
It is true that the use of $GLOBALS['TYPO3_DB'] is easier.

Related

Add data to TYPO3 Repository Extbase

I want to develop an extension for TYPO3 6.2.
In the controller class I created a action called "fetchFeUsersAction".
This action loads a set of data from the table fe_users in the table which was created from the extensionbuilder from the model.
The function to the get the users in the Repository looks like this:
public function getFeUsers()
{
/** #var Query $q */
$q = $this->createQuery();
$q->statement('SELECT * from fe_users');
$data = $q->execute(true);
return $data;
}
This works very fine.
But now I want to store the results from the table fe_users in my model with this action:
public function fetchFeUsersAction()
{
$data = $this->adressRepo->getFeUsers();
foreach ($data as $feuser) {
/** #var Adresse $address */
$address = $this->objectManager->get(Adresse::class);
$q= $this->adressRepo->createQuery();
$q->matching(contains('email', $feuser['email']));
$contain= $q->execute();
if($contain==NULL){
$address->setEmail($feuser['email']);
$this->adressRepo->add($address);
}
}
$this->redirect('list');
}
Here I want to check if the email adress is already stored in my table.
If the email adress is not stored it should be added to the model.
But it doesnt work. Even with an empty table. Without the condition it works very fine.
Extbase persists the complete data into the DB later. You need to persist manually i think, like this:
/** #var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager */
$persistenceManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class);
$persistenceManager->persistAll();
Not currently tested, just copied it from my of my extensions. but in there i had the same problem to check if it exists.
Hope this helps a little bit.

TYPO3 Hook for Page/ Content

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

Extbase property mapping for deleted record

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 :-)

Extbase update deleted=1 object in Controller fails (Object with identity x not found)

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.

How does Zend_Auth storage work?

This is very simple. I write
$auth->getStorage()->write($user);
And then I want, in a separate process to load this $user, but I can't because
$user = $auth->getIdentity();
is empty. Didn't I just... SET it? Why does it not work? Halp?
[EDIT 2011-04-13]
This has been asked almost two years ago. Fact is, though, that I repeated the question in July 2010 and got a fantastic answer that I back then simply did not understand.
Link: Zend_Auth fails to write to storage
I have since built a very nice litte class that I use (sometimes with extra tweaking) in all my projects using the same storage engine as Zend_Auth but circumventing all the bad.
<?php
class Qapacity_Helpers_Storage {
public function save($name = 'default', $data) {
$session = new Zend_Session_Namespace($name);
$session->data = $data;
return true;
}
public function load($name = 'default', $part = null) {
$session = new Zend_Session_Namespace($name);
if (!isset($session->data))
return null;
$data = $session->data;
if ($part && isset($data[$part]))
return $data[$part];
return $data;
}
public function clear($name = 'default') {
$session = new Zend_Session_Namespace($name);
if (isset($session->data))
unset($session->data);
return true;
}
}
?>
It's supposed to work.
Here's the implementation of the Auth getIdentity function.
/**
* Returns the identity from storage or null if no identity is available
*
* #return mixed|null
*/
public function getIdentity()
{
$storage = $this->getStorage();
if ($storage->isEmpty()) {
return null;
}
return $storage->read();
}
Here's the implementation of the PHP Session Storage write and read functions:
/**
* Defined by Zend_Auth_Storage_Interface
*
* #return mixed
*/
public function read()
{
return $this->_session->{$this->_member};
}
/**
* Defined by Zend_Auth_Storage_Interface
*
* #param mixed $contents
* #return void
*/
public function write($contents)
{
$this->_session->{$this->_member} = $contents;
}
Are you sure you are loading the same instance of the Zend_Auth class?
Are you using
$auth = Zend_Auth::getInstance();
Maybe you are calling the write method after the getIdentity method?
Anyway, as I said before, what you are doing should work.
So on a page reload you can fetch the session, while not if redirecting? Are you redirecting on a different Domain-Name? Then it might be an issues with the Cookies and you'd need to manually set session.cookie_domain ini variable.
Check if the cookie named PHPSESSID has been properly been set and if it's being sent to the server on every page request? Is it constant or does it change on every request?
Also, you might want to check if the session data is being properly saved to the disk. The sessions can be found in the directory defined by the ini variable session.save_path. Is the file corresponding to your PHPSESSID there and does it contain a meaningful entry? In my case it contains
root#ip-10-226-50-144:~# less /var/lib/php5/sess_081fee38856c59a563cc320899f6021f
foo_auth|a:1:{s:7:"storage";a:1:{s:9:"user_id";s:2:"77";}}
Add:
register_shutdown_function('session_write_close');
to index.php before:
$application->bootstrap()->run();