Typo3 Define storagePid for CommandController command - typo3

I would like to import different data using a CommandController (scheduler).
I allready figured out that it is possible to set a global storagePid like:
module.tx_myextension.persistence.storagePid = 123
source: https://worksonmymachine.org/blog/commandcontroller-and-storagepid
That works fine, but my extension contains multiple models which should be saved on different Pid's
I also found an old post where someone said it is possible to define a pid for each model which would be exactly what I need:
module.tx_myextension.persistence.classes.tx_myextension_domain_model_player.storagePid = 124
module.tx_myextension.persistence.classes.tx_myextension_domain_model_customer.storagePid = 125
source: https://typo3-german.typo3.narkive.com/WxjjtxXa/scheduler-storage-pid
But it seems like this lines get ignored. Is this the correct way or do I do something wrong?
I am on TYPO3 6.2.44

I suggest to create params for the controller action. For each model a storage pid.
so you have myCommand($domain1Pid, $domain2Pid,$domain3Pid, ...)
Now as first call in your function you get the querySettings for the repositories and apply the storage pids:
$querySettings = $this->domain1Repository->createQuery()->getQuerySettings();
$querySettings->setStoragePageIds([$domain1Pid]);
$this->domain1Repository->setDefaultQuerySettings($querySettings);
repeat this for each repository. In the scheduler job settings or cli you can now define the pids for each storage.
btw: you can also use $domain->setPid(123) to set the pid of each model where to save.

Related

Access related model fields from ModelAdmin actions for exporting to excel

I am desperately waiting for someone attention to get my question answered.... please help..
ModelAdmin model has to export to Excel action method.
I need to access related model fields in action method. That means I can not pass any arguments therefore I tried relatedmodel_set but ModelAdmin action method shows memory location and fails when I try to access values through attributes:
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager..RelatedManager object at 0x7f8eea904ac0>
model.py
class EnrolStudent(models.Model):
def get_trn_activity(self):
return self.studenttraininactivities_set
class StudentTraininActivities(models.Model):
trainin_activities = models.ForeignKey(EnrolStudent,
on_delete=CASCADE, null=True )
<other fields...>
admin.py
#admin.register(EnrolStudent)
class EnrolAdmin(admin.ModelAdmin):
form = CityInlineForm
inlines = [CohortTraininActivitiesInline]
...
actions = [export_as_txt_action_0120("File NAT00120 data Export"
, fields=['information_no', 'get_trn_activity',
'student_enrol__student_code'])]
I need to access related model fields to export to excel.
I can not pass parameter to get_trn_activity as you have noticed.
Therefore selected rows only data from Django admin change_list page will only need bit of work using its queryset in actions method used in separate actions.py file that I can do!
Please help me with this issue. I am new to Python / Django.
I also tried property decorator in related model then access in a method in main model then call it inside action but same problem with memory address not the direct value and then how to get data of memory location here .... I don't know.
If I can access the related fields then I can do it no issue.
Another question:
I had same situation with model/related model before, but they were connected through OneToOneField relationship and I was able to use dundor to access related model fields but in this case of ForiegnKey relationship I can not see related model in queryset.
In other case this is what I can do easily; here cohortdetails is related model and when I debug I saw it was listed in queryset that was great.
actions = [export_as_txt_action_0080("File NAT00080 txt Export",
fields=['rto_student_code', 'first_name', 'family_name'
,'cohortdetails__highest_school__highestschool_levelcode',
'cohortdetails__cohort_gender'
, 'cohortdetails__student_dob' ])]

Retrieving the BackendUser from BackendUserAuthentication

I'm trying to develop an extension that adds a Button to the ClearCache menu in the TYPO3 Backend. In a large installation with multiple domains, non-admin users need a button to clear the page cache for their domain, but only of those pages that they have access to. The default options.clearCache.pages = 1 instead flushes the whole Frontend Cache of the installation.
I've gotten so far as to calling a method in a custom class ClearCacheHook, that implements \TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface.
I next need to get a list of all page uids the BackendUser has access to, which is done with $backendUser->getDbMountPoints(). All the docs speak of a global variable $BE_USER, but this isn't set for me. I have a $GLOBALS['BE_USER'], but that is of the class BackendUserAuthentication.
I can't figure out how to resolve the BackendUser from the BackendUserAuthentication. Theres the BackendUser uid in the object so I tried initializing a TYPO3\\CMS\\Beuser\\Domain\\Repository\\BackendUserRepository via the ObjectManager, but that fails.
I'll focus on the more specific tasks: Create an instance of BackendUserRepository and create an instance of BackendUser from uid.
You might have a look at the UsernameViewHelper.php class of be_log in the TYPO3 core.
specifically this:
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Repository\BackendUserRepository;
use TYPO3\CMS\Extbase\Object\ObjectManager;
...
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$backendUserRepository = $objectManager->get(BackendUserRepository::class);
/** #var \TYPO3\CMS\Extbase\Domain\Model\BackendUser $user */
$user = $backendUserRepository->findByUid($uid);
If there is something, I don't find in the documentation, I sometimes look at existing extensions. A good candidate is the news extensions. Other good candidates are, of course, the TYPO3 source code.

TYPO3: repository->findAll() not working

I am building an extension with a backend module. When I call the findAll() method it returns a "QueryResult" object.
I tried to retrieve objects with findByUid() and it does work.
I set the storage pid in the typoscript:
plugin.tx_hwforms.persistence.storagePid = 112
I can also see it in the typoscript object browser.
I also added this to my repository class:
public function initializeObject()
{
$defaultQuerySettings = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class);
$defaultQuerySettings->setRespectStoragePage(false);
$this->setDefaultQuerySettings($defaultQuerySettings);
}
so that the storage pid is ignored ...
It's still not working, findAll doesn't return an array of entites as it should
Repository must return a QueryResult from the findAll methods. Only methods which return a single object (findOneByXYZ) will return anything else.
All of the following operations will cause a QueryResult to load the actual results it contains. Until you perform one of these, no results are loaded and debugging the QueryResult will yield no information except for the original Query.
$queryResult->toArray();
$queryResult->offsetGet($offset); and $queryResult[$offset];
$queryResult->offsetExists($offset);
$queryResult->offsetSet($offset, $value); and $queryResult[$offset] = $value; (but be aware that doing this yourself with a QueryResult is illogical).
$queryResult->offsetUnset($offset); and unset($queryResult[$offset]); (again, illogical to use this yourself)
$queryResult->current(), ->key(), ->next(), ->prev(), ->rewind() and ->valid() which can all be called directly or will be called if you begin iterating the QueryResult.
Note that ->getFirst() and ->count() do not cause the original query to fire and will not fill results if they are not already filled. Instead, they will perform an optimised query.
Summa summarum: when you get a QueryResult you must trigger it somehow, which normally happens when you begin to render the result set. It is not a prefilled array; it is a dynamically filled Iterator.
This should work.there must be issue with your storage page in FindAll() extbase check for storage but in findByXXX() it ignore storage.
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\Extbase\\Object\\ObjectManager');
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->cityRepository->setDefaultQuerySettings($querySettings);
$cities = $this->cityRepository->findAll();
Use additionally typoscript module configuration, like
module.tx_hwforms.persistence.storagePid = 112
Ensure your Typoscript is loaded in root. For BE modules I prefere to use
EXT:hwforms/ext_typoscript_setup.txt
where you write your module and extbase configuration.
Try to debbug like below and check findAll() method present for this repositry. I think this is useful for you click here
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(get_class_methods($this->yourRepositryName)); exit();
Afetr added all your changes once you need to uninsatll/install extension.
I would inspect the generated query itself. Configure the following option in the install tool:
$GLOBALS["TYPO3_CONF_VARS"]["sqlDebug"]
Note: dont do this in production environemnt!!
Explanation for sqlDebug:
Setting it to "0" will avoid any information being print on screen.
Setting it to "1" will show errors only.
Setting it to "2" will print all queries on screen.
So in Production you want to keep it at "0", in development environments you should set it to "1", if you want to know why some result is empty, configure it to "2".
I would guess that some enablefield configuration causes your problem.
If you retrieve an object by findByUid you will have the return because enablefields are ignored. In every other case enablefields are applied and that may cause your empty result.

Extbase Hooks - execute code upon record creation

I want to create a standard typo3 extension but when I create a record (or modify it) I want to calculate something (in my case I want to call the Google Map API to get coordinates from a given address).
SO I search for a hook or something. Any idea?
One of my project example, may helps you for hook in backend when record has been changed.
In your extension file ext_localconf.php
// Hook for cancellation
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:femanager/class.tx_femanager_tcemainprocdm.php:tx_femanager_tcemainprocdm';
hook file class.tx_femanager_tcemainprocdm.php where you can execute
your script
class tx_femanager_tcemainprocdm{
function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$reference){
// $status also called action like delete
// $table - table name of excute backend action
// $id - record UID
// $fieldArray - fields of your table
if($table = 'your_extension_table_name'){
// your script
}
}
}
Maybe this answer is useful to you.
Register your class as a data handling hook in your extension. This one "is called AFTER all commands of the commandmap" were executed. Maybe you need to look for a more appropriate one.
Then in your registered Hook i.e. 'typo3conf/ext/your_ext/Classes/Hooks/AfterCreate.php' do your calculation. Hope this sets you on the right track.
In my special case there was no need to calculate the coordinates when the record got saved. So I just used the listAction in the controller, check if coordinates are there and if not call the Google API (and send an email if the Google API does not give a coordinate back).
In another case where the new record comes from a frontend plugin and I had to do something with this data I used the createAction in the Controller. (I am not sure if the createAction is also called when the record is created from the backend.)

Symfony form gets messy when calling getObject() in form configuration

I have a Strain model that has a belongsTo relationship with a Sample model, i. e. a strain belongs to a sample.
I am configuring a hidden field in the StrainForm configure() method this way:
$defaultId = (int)$this->getObject()->getSample()->getTable()->getDefaultSampleId();
$this->setWidget('sample_id', new sfWidgetFormInputHidden(array('default' => $defaultId)));
Whenever I create a new Strain, the $form->save() fails. The debug toolbar revealed that it tries to save a Sample object first and I do not know why.
However, if I retrieve the default sample ID using the table it works like a charm:
$defaultId = (int)Doctrine_Core::getTable('Sample')->getDefaultSampleId();
$this->setWidget('sample_id', new sfWidgetFormInputHidden(array('default' => $defaultId)));
My question here is what can be happening with the getObject()->getSample()... sequence of methods that causes the StrainForm to think it has to save a Sample object instead of Strain.
I tried to debug with xdebug but I cannot came up with a clear conclusion.
Any thoughts?
Thanks!!
When you call getSample its creating a Sample instance. This is automatically attached to the Strain object, thus when you save you also save the Sample.
An altenrative to calling getSample would be to chain through Strain object to the Sample table since i assume youre only doing this so your not hardcodeing the Sample's name in related form:
// note Sample is the alias not necessarily the Model name
$defaultId = Doctrine_Core::getTable($this->getObject()->getTable()->getRelation('Sample')->getModel())->getDefaultId();
Your solution probably falls over because you can't use getObject() on a new form (as at that stage the object simply doesn't exist).
Edit: Why don't you pass the default Sample in via the options array and then access it from within the form class via $this->getOption('Sample') (if I remember correctly)?