TYPO3 persistAll() not working with AJAX call - typo3

I want to update a database record like this:
$persistenceManager = $this->objectManager->get("TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager");
$person->setStatus(1);
$this->personRepository->update($person);
$persistenceManager->persistAll();
When I add a redirect everything works as expected. But when I call the controller as an AJAX request it's not updating the record.
I read on this documentation that i just need to add
$persistenceManager->persistAll();
after my update. But it's still not working.
I want to find out why it's not updating.

Not sure that all objects are correctly instantiate through an Ajax call, may be you can try something like this :
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$person->setStatus(1);
$personRepository = $objectManager->get(PersonRepository::class);
$personRepository->update($person);
$persistenceManager = $objectManager->get(PersistenceManager::class);
$persistenceManager->persistAll();

Related

Typo3: Controller action with hidden record as its parameter

I am currently trying to get a extension working in Typo3 v10, which enables the user to show, edit, update, disable and enable other user accounts.
Unfortunately, I am running into the issue that I cannot use disabled users as arguments for the actions:
/**
* Save user changes
*
* #param \Company\MyExtension\Domain\FeUser $feuser
* #return void
*/
public function updateAction(\Company\MyExtension\Domain\FeUser $feuser): void {}
It would resulting in the error following error:
Object of type \Company\MyExtension\Domain\FeUser with identity "3" not found.
From what I have gathered, extbase does not rely on the repository's default query settings to create the objects but instead uses PersistenceManager::createQueryForType to get the query settings via QueryFactory::create. This is an issue also listed in a few bug reports.
There's a suggestions as to how to use a custom QueryFactory to set different default QuerySettings for my extension, however this does not seem to work in Typo3 v10 anymore, at least my custom QueryFactory isn't being used after registering it... Also, if this were to work, wouldn't it use the new QueryFactory for all objects instantiated through a controller action and not just this extension?
How can I properly handle hidden users my extension with Typo3 v10.4?
P.S. Another suggestion was to fetch object early through initializeAction, but this only works well if it is about the unmodified model and not when setting new values for the object, as it would just load the database values in the end...
Checkout the extension "news" how it is handled here:
if ($news === null || $this->settings['isShortcut']) {
$previewNewsId = ((int)$this->settings['singleNews'] > 0) ? $this->settings['singleNews'] : 0;
if ($this->request->hasArgument('news_preview')) {
$previewNewsId = (int)$this->request->getArgument('news_preview');
}
if ($previewNewsId > 0) {
if ($this->isPreviewOfHiddenRecordsEnabled()) {
$news = $this->newsRepository->findByUid($previewNewsId, false);
} else {
$news = $this->newsRepository->findByUid($previewNewsId);
}
}
}
https://github.com/georgringer/news/blob/master/Classes/Controller/NewsController.php#L338
I am assuming you need the URL as well. I gave an answer here if you wanna take a look.
Show, edit and update hidden records in FrontEnd (TYPO3)
You can adjust it to your own needs as well.
Best regards

Remove submitted state in submission handler

I am trying to reset a form so that it appears to Drupal 8 that it hasn't been submitted. So far I have been unable to do this, as I cannot find any available methods (setSubmitted() hardcodes it to TRUE without a FALSE option). The reason is this isn't a full submit, but a submit of one field after which I would like the user to be redirected to another page that has another form, and I would like this secondary form to use the value obtained in the first step.
In the submit handler for the first part I use this to redirect:
$form_state->setRedirect('my.route', [], []);
And this works, but when the form reaches the second form (it seems) that the second form thinks it is a submission. As a result any submit buttons I add to the second form seem to make it auto-submit, and this breaks my user journey.
In the submit for the first part I have tried:
$form_state->setRebuild(TRUE);
$form_state = new FormState();
unset($form_state);
Tried the above in various configurations to no avail. They all prevent/ignore the setRedirect call that I make afterwards. The reason I want/need to do it this way is I want to preserve the POST method used.
Do you want to obtain something similar to what core search module does? It has simple SearchBlockForm that sends data to more complex SearchPageForm.
SearchBlockForm uses GET method (though you may use POST):
$form['#method'] = 'get';
and has no id and token fields:
function search_form_search_block_form_alter(&$form, FormStateInterface $form_state) {
$form['form_build_id']['#access'] = FALSE;
$form['form_token']['#access'] = FALSE;
$form['form_id']['#access'] = FALSE;
}
BTW, the last change allows you to avoid running submit callbacks.
Hope this helps.

Where should I create a template for a json view in CakePHP 3?

I am using CakePHP 3.1 and trying to render the json index response for User model. I followed the CakePHP manual page and created index.ctp under the directory src/Template/Users/json/, but the file does not get hooked by the controller. I also tried src/View/Users, which also did not work. Should I specify a file to render or something else? In src/Controller/UsersController.php, I have index() method with
$users = $this->paginate('Users');
$this->set(compact('users'));
Check your AppController.php. Since version 3.1.0 this sets the _serialize to true by default. Therefore the template files are all ignored.
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
}
You need to remove that code from beforeRender.

TYPO3 extbase - get "uid" of non persisted object

Just started out with the frst extbase extension. In localconf I added these actions: 'list, new, show, create, edit'.
Default was that "create" redirected to "list" with no arguments, and that worked fine right after creation of the extension.
$this->redirect('list'); // <- this works if used
But instead of redirecting to "list" I would like to redirect to "show" to display the newly added priceFormCalc. A collegue helped me to acomplish this using persist.
Below is the code and it works. But reading on the net it seem that it should not be best practice to run persist. It should be doable to call the action show without manually persisting first.
So question is: Is this the correct way to do it, or is there a more "ext base" way show a newly created record?
public function createAction(\TYPO3\OgNovomatrixpricecalc\Domain\Model\PriceCalcForm $newPriceCalcForm) {
$this->priceCalcFormRepository->add($newPriceCalcForm);
$this->flashMessageContainer->add('Your new PriceCalcForm was created.');
// workaround - or the right way?
$persistenceManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('Tx_Extbase_Persistence_Manager');
$persistenceManager->persistAll(); // <- save i database
$uid = $newPriceCalcForm->getUid(); // <- get UID of newly saved record
// do redirect using uid of newly created priceCalcForm
$this->redirect('show',Null,Null, array('priceCalcForm' => $uid));
}
To
You can persist the current state and then get the uid. Inject the configuration manager (TYPO3 6.x way):
/**
* persistence manager
*
* #var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
* #inject
*/
protected $persistenceManager;
Then use
$this->persistenceManager->persistAll();
to apply all changes. Then you can pass your object (or only the uid) to the action.

Zend Framework 1.12, execution of raw SQL inserts the same record twice

I know there´s a similar situation in stack, and I´ve already checked it out and the answers have not guided me to mine.
Here´s the deal:
I need to execute raw SQL, an INSERT to be precise. I have multiple values to insert as well. No problem since Zend let´s you use "query" from Zend_Db_Table (I use my default adapter, initialized in my application.ini file).
$db_adapter = Zend_Db_Table::getDefaultAdapter();
....query gets built...
$stmt = $db_adapter->query($query);
$stmt->execute();
When doing var_dump($query); this is what I see:
INSERT INTO tableName (col1,col2,col3) VALUES ('value1', 'value2', 'value3')
I have already tried the following:
I have no "manifesto" attribute on the html page rendered
I have looked at the network both with Chrome and Firefox to see the POSTS/GETS getting sent, and the controller whose actions does
this INSERT gets called once with a POST.
It is true that I call a viewscript from another action to be rendered, like so:
$this->renderScript('rough-draft/edit.phtml');
I don´t see how that could affect the statement getting executed twice.
I know it gets executed twice:
Before the POST is sent, the data base has nothing, clean as a whistle
POST gets sent, logic happens, from is rendered again
Data base now has the same record twice (with the name that has been inserted from the POST), so it´s not a rendering problem
It has to do with the way I am executing raw SQL, because if I use ->insert($data) method that comes with Zend_Db_Table_Abstract (obviously I declare a class that extends from this abstract one and bind it to the appropriate table) it does not insert the record twice. Thing is, I want to use raw SQL.
I really appreciate your help!
Expanded as requested:
Controller code:
public function saveAction()
{
$request = $this->getRequest();
if (!$request->isPost())
$this->_sendToErrorPage();
$this->_edit_roughdraft->saveForm($request->getPost());
$this->view->form = $this->_edit_roughdraft->getForm();
$this->renderScript('rough-draft/edit.phtml');
}
Code from model class (in charge of saving the form from the data in POST):
public function saveForm($form_data) {
$db = new Application_Model_DbTable_RoughDrafts();
$id = $form_data['id'];
$db->update($this->_get_main_data($form_data), array('id=?' => $id));
/* Main data pertains to getting an array with the data that belongs to yes/no buttons
* and text input. I need to do it as so because the other data belongs to a dynamically
* built (by the user) multi_select where the options need to be deleted or inserted, that
* happens below
*/
$multi_selects = array('responsables', 'tareas', 'idiomas', 'habilidades', 'perfiles');
foreach($multi_selects as $multi_select){
if(isset($form_data[$multi_select]) && !empty($form_data[$multi_select])){
$function_name = '_save_'.$multi_select;
$this->$function_name($form_data[$multi_select], $id);
}
}
$this->_form = $this->createNewForm($id, true);
//The createNewForm(..) simply loads data from data_base and populates form
}
I do want to make clear though that I have also used $db->insert($data), where $db is a class that extends from Zend_Db_Table_Abstract (associated to a table). In this case, the record is inserted once and only once. That´s what leads me to believe that the problem lies within the execution of my raw sql, I just don´t know what is wrong with it.
I should have done this from the beginning, thanks for the help everyone, I appreciate your time.
I knew the problem was with my syntax, but I didn´t know why. After looking at different examples for how people did the raw sql execution, I still didn´t understand why. So I went ahead and opened the class Zend_Db_Adapter_Abstract in Zend library and looked for the 'query()' method I was using to get the statement to execute.
public function query($sql, $bind = array())
{
...some logic...
// prepare and execute the statement with profiling
$stmt = $this->prepare($sql);
**$stmt->execute($bind);**
// return the results embedded in the prepared statement object
$stmt->setFetchMode($this->_fetchMode);
return $stmt;
}
So the ->query(..) method from the Zend_Db_Adapter already executes said query. So if I call
->execute() on the statement that it returns, I'll be the one causing the second insert.
Working code:
$db_adapter = Zend_Db_Table::getDefaultAdapter();
....query gets built...
$db_adapter->query($query);