Hooks: processDatamap_preProcessFieldArray() - extbase

I am about porting an Extention from T3-6.2 to T3-7.6+
public function processDatamap_preProcessFieldArray(
&$fieldArray, $table, $id,
\TYPO3\CMS\Core\DataHandling\DataHandler &$pObj
) {
// t3_origuid is set? Yes, ist a Copy
if(isset($fieldArray['t3_origuid']) && $table=='mytable') {
$fieldArray['field1']++;
$fieldArray['filed2']--;
}
}
BUT:
To tell if it is a copy or not this needs the field 't3_origuid' in my record. It is not a standard field but if present it is filled by typo3.
Where does this filed come from? My I use this witout further problems?
If you know a hook/better way, (Slot, Signal?) to use in this case in T3 7.6+ please let me know.
Thanks a lot,
Christian.

This field is used by the sys extension workspace. If you change a tt_content element inside a workspace the original uid will be stored inside the field. So the changes,when they will be published, can be applied to the original element.

Related

Simpler way to get advanced meta data in ilUIHookPluginGUI?

I am currently coding a plugin for ILIAS. The plugin itself is not at all complex but it contains several issues whereas I think we could make it simpler as it is.
The situation is following: We have a global advanced meta data field added in the user defined meta data section with a bijective identifier. The field is activated at a repository objected named course. We have manipulated the GUI with the plugin based on ilUIHookPluginGUI.
The code for this is ... well ... see it for yourself.
First of all we save the ID of the new meta data field in the settings at the ConfigGUI for the plugin:
$field_settings = new ilSetting("foo");
$field_id_value = $field_settings->set("field_id",$_POST["field_id"]);
In our class which extends ilUIHookPluginGUI we are loading the setting as following and we have the ID of the field:
$field_settings = new ilSetting("foo");
$field_id_value = $field_settings->get("field_id");
Now the fun part. With this ID and the ref_id of the object (well, we also load the object to get the ObjId) we can load the value of the meta data field setted at the course:
$object = \ilObjectFactory::getInstanceByRefId($_GET[ 'ref_id' ]);
$obj_id = $object->getId();
$result = $DIC->database()->query("SELECT value FROM adv_md_values_text WHERE obj_id = '".$obj_id."' AND field_id = '".$field_id_value."'");
$value = $DIC->database()->fetchAssoc($result);
$is_active = $value['value'];
The question is ... is there an easier way to achieve my result?
Best,
Laura
Nice question. First of all, note that I consider the advanced metadata service in ILIAS to be lacking a good readme making clear, which hooks the interface is offering for tasks such as yours. Some time ago, I had to deal with this service as well and run into similar issues. Hopefully, your question helps to document this a little better an I myself am looking forward to other suggestions, knowing that mine is not really good as well. If you have any resources, helping pushing the introduction of good readme for services and also pushing services towards using the repository pattern with a clear interface would be highly appreciated.
Concering your question of what can be improved: I see three main issues in the lines of code:
Storing an ID in the config of your plugin. Your plugin will unconfigurable for non-technical people. However, also for you this will be error prone, think about exporting-importing stuff from a test-installation to production.
Access the value by query instead of the service.
Using new and static functions inside your code making it untestable.
Step 1
Lets start with the first one. Note, that I did not manage to solve this one without introducing a new one (a new query). Bad I know. I hope that there is a better solution, I did not find one after quick research. You store the id, since the field title is not securely unique, right? This is correct, however, you could think about storing the tripplet of field_title, record_title and (maybe) scope. Note that you maybe do not need the scope since you want to use this globally. A function return you and array containing field_id and record_id could look like so:
function getFieldAndRecordIdByFieldTitles($field_title, $record_title, $scope_title){
$query = "select field.field_id,field.record_id from adv_mdf_definition as field
INNER JOIN adv_md_record as record ON record.record_id = field.record_id
INNER JOIN adv_md_record_scope as scope ON scope.record_id = field.record_id
INNER JOIN object_reference as ref ON scope.ref_id = ref.ref_id
INNER JOIN object_data as scope_data ON ref.obj_id = scope_data.obj_id
WHERE field.title='$field_title' AND record.title='$record_title' AND scope_data.title = '$scope_title'";
$set = $this->dic()->database()->query($query);
if($row = $this->dic()->database()->fetchAssoc($set))
{
return array_values($row);
}
}
Then get your values like so:
list($field_id,$record_id) = getFieldAndRecordIdByFieldTitles("my_field", "my_record", "my_scope");
Note that I am aware that I am introducing a new query here. Sorry, was the best I could come up with. I am sure there you find a better solution, if your research a bit, let us know if successful. However, we will remove one in the next step.
Step 2
Use the undocumented service, the get your value out of the advance meta data. Since you now have the record id and the field id, you can to that like so:
$record_values = new ilAdvancedMDValues($record_id, $obj_id);
$record_values->read();
$ADTGroup = $ilAdvancedMDValues->getADTGroup();
$ADT = $ilADTGroup->getElement($field_id);
$value = $ADT->getText();
/**if you have text, others are possible, such as:
switch (true) {
case ($ADT instanceof ilADTText):
break;
case ($ADT instanceof ilADTDate):
$value = $ADT->getDate();
break;
case ($ADT instanceof ilADTExternalLink):
$... = $ADT->getUrl();
$... = $ADT->getTitle();
break;
case ($ADT instanceof ilADTInternalLink):
$... = $ADT->setTargetRefId($value);
}
**/
Note that ADT's are also undocumented. There might be a better way, to get a value out of this.
Step 3
Wrap your statics and new into some injectable dependency. I usually use the bloated constructor pattern to do this. Looks like so:
public function __construct(InjectedSettings $mySettings = null)
{
if (!$mySettings) //Case in the default scenario
{
$this->mySettings = new InjectedSettings();
} else //used e.g. for unit tests, where you can stuff the constructor with a mock
{
$this->mySettings = $mySettings;
}
$this->mySettings->doSometing();
}
Note that this is not real dep. injection, still you still use new, but I think a very workable fix to use dep. injection at least for the test context in ilias.
Does this help? I hope there will be other (better answers as well).

Some property object are null

I have a problem and of course i dont understand :) (and of course im french :)
On a table "evenement" i have a user linked.
And When i do :
$repository = $this->getDoctrine()->getManager()->getRepository('AppBundle:Evenement');
$evt = $repository->findOneById($evt);
dump($evt)
All is ok, i can read my evt, but when in profiler i click on a child object "user", all property are null (except id, usermail, mail, password)
and its the same thing when i do :
dump($evt->getUser());
Why all property are not filled ?
thank you and sorry for my english.
It's most probably Lazy Loading. Properties are not beeing read from DB unless you need them.
Try to do the following:
$repository = $this->getDoctrine()->getManager()->getRepository('AppBundle:Evenement');
$evt = $repository->findOneById($evt);
$evt->getUser()->getRoles(); // Ot whatever properties your user has.
dump($evt)
In this case, dump will show this property populated.

Drupal 7 | Preserve file after entity_wrapper unset?

Question is quite simple: How to preserve file on server and in file tables, so its fid is still valid after unsetting/changing value with entity wrapper?
$ewrapper = entity_metadata_wrapper('node', $sourceNode);
unset($sourceNode->field_image[$sourceNode->language][0]);
$ewrapper->save();
Now the related file is deleted as soon as the above is called. Same happends if I use:
$ewrapper->field_image->set($newImage);
In this case I need to keep the old image.
Thanks for your help guys!
I think that you should change file status from FILE_STATUS_TEMPORARY to FILE_STATUS_PERMANENT. Check out this answer here:
https://api.drupal.org/comment/23493#comment-23493
Basically, there is no file_set_status() function, like Drupal 6 had one, but now this code should do the same job:
// First obtain a file object, for example by file_load...
$file = file_load(10);
// Or as another example, the result of a file_save_upload...
$file = file_save_upload('upload', array(), 'public://', FILE_EXISTS_REPLACE);
// Now you can set the status
$file->status = FILE_STATUS_PERMANENT;
// And save the status.
file_save($file);
So, you load file object one or another way, change it's status property and save object back again.

How can I remove a message shown from a different module?

In Drupal 7, I could use the following code.
if ($_SESSION['messages']['status'][0] == t('Registration successful. You are now logged in.')) {
unset($_SESSION['messages']['status']);
}
What is the equivalent code for Drupal 8?
First of all, in Drupal 8, messages are stored in the same $_SESSION['messages'] variable as before. However, using it directly is not a good way, as there exist drupal_set_message and drupal_get_messages functions, which you may freely use.
Then, status messages are shown using status-messages theme. This means that you can write preprocess function for it and make your alteration there:
function mymodule_preprocess_status_messages(&$variables) {
$status_messages = $variables['message_list']['status'];
// Search for your message in $status_messages array and remove it.
}
The main difference with Drupal 7, however, is that now status messages are not always strings, they may be objects of Markup class. They are wrappers around strings and may be cast to underlying string using magic method __toString. This means that they can be compared with and as strings:
function mymodule_preprocess_status_messages(&$variables) {
if(isset($variables['message_list']['status'])){
$status_messages = $variables['message_list']['status'];
foreach($status_messages as $delta => $message) {
if ($message instanceof \Drupal\Component\Render\MarkupInterface) {
if ((string) $message == (string) t("Searched text")) {
unset($status_messages[$delta]);
break;
}
}
}
}
}
Upon reading the related change record, I have discovered \Drupal::messenger()->deleteAll(). I hope this is useful to someone. UPDATE: You should NOT do this, as it removes all subsequent messages as well. Instead, do unset(['_symfony_flashes']['status'][0]).
You can install the module Disable Messages and filter out messages by pattern in the configuration of the module.
For this particular case, you can filter out the message using the following pattern in the module configuration
Registration successful.*
Although the question is asked around Drupal 8 which is no longer supported, the module works for Drupal 7, 8, 9.
You can solve your problem in more than one way.
First way:
You can make minor change in core user module.
Go on:
\core\modules\user\src\RegisterForm.php
In that file you have line you can change:
drupal_set_message($this->t('Registration successful. You are now logged in.'));
NOTE: This is easiest way but in this case way you will edit Drupal core module and that is generally bad practice. In further development you could have problems like overwrite your changes when you do update.
Second way:
You can disable end user message using module. Disable message module have option you need. In module configuration you have text box where you can filter out messages shown to the end users.
Third way:
Messages in Drupal 8 are stored in a session variable and displayed in the page template via the $messages theme variable. When you want to modify the variables that are passed to the template before it's invoked you should use preprocess function. In your case here you can just search string in session variable and alert/remove it before it's displayed.
function yourmodule_preprocess_status_messages(&$variables) {
$message = 'Registration successful. You are now logged in.';
if (isset($_SESSION['messages'])) {
foreach ($_SESSION['messages'] as $type => $messages) {
if ($type == 'status') {
$key = array_search($message, $messages);
if ($key !== FALSE) {
unset($_SESSION['messages'][$type][$key]);
}
}
}
}
}
(Note:Untested code, beware of typos)
Hope this helps!

How to do empty list check in maximo anywhere

I am getting few json response from service as "-##EmptyComplexField##-". Due to which screen crashes. How to do a proper empty check for complex feild in maximo anywhere. Please help with sample code.
We can do a empty check for list as below
if(list && list!="-##EmptyComplexField##-")
Not sure why you're getting this EmptyComplexField string down at your layer. Are you sure you've defined your multiplicity correctly on the OSLC Resources app for these new children objects?
if (/-or-many$/.test(complexAttribute.multiplicity)){
var attributeName = complexAttribute.remoteName;
if (!(attributeName in data)){
Are you making sure these complexattributes are set as requiredattributes on the view before you display it?
The most correct answer would be:
if (list && list != PlatformConstants.EMPTY_COMPLEX_FIELD) { ... }

Resources