TYPO3 TCA userfunc - typo3

Kinda stuck.
We have products which we offer to companies.
so it would be an mm field which is no problem to implement, but the problem comes with date, since each product has expire date based on company.
so decided to remove product mm and put product id with date into company as one field.
but since input which we send is an array it's not possible to save it there.
How can i solve this problem ?
this is my tca for that field:
'product' => [
'exclude' => true,
'label' => 'LLL:EXT:wemessage_checklist/Resources/Private/Language/locallang_db.xlf:tx_wemessagechecklist_domain_model_company.product',
'config' => [
'type' => 'user',
'userFunc' => Wemessage\WemessageChecklist\UserFunc\Checklist::class.'->renderChecklists',
],
],
Here is function to render html:
public function renderChecklists($PA, $fObj){
$checked = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_wemessagechecklist_domain_model_company', 'hidden=0 and deleted=0 and uid='.$PA['row']['uid'].' and pid='.$PA['row']['pid']);
$allProducts = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_wemessagechecklist_domain_model_product', 'hidden= 0 and deleted = 0');
foreach($allProducts as $product){
$html .= '<div>';
$html .= '<input type="hidden" name="data[tx_wemessagechecklist_domain_model_company]['.$PA['row']['uid'].'][product]['.$product['uid'].']" class="product"/>';
$html .= '<input type="checkbox" class="tocheck" value="'.$product['uid'].'" /><span style="margin: 0 10px;">'.$product['name'].'</span><span style="margin: 0 10px;">Verval datum</span><input type="date" class="date" />';
$html .= '</div>';
}
$html .= '<script>
TYPO3.jQuery(".tocheck").click(function(){
var val = TYPO3.jQuery(this).val();
if(TYPO3.jQuery(this).prop("checked")){
TYPO3.jQuery(this).parent().find(".product").val(val);
}
});
TYPO3.jQuery(".date").change(function(){
var x = new Date(TYPO3.jQuery(this).val()).getTime();
var b = TYPO3.jQuery(this).parent().find(".product").val();
TYPO3.jQuery(this).parent().find(".product").val(b+":"+x);
});
</script>';
return $html;
}
probably another option is to implement AJAX calls to process data in standalone table. although if there is another solution will be glad to hear it.

You should still go for an MM relation or better inline (IRRE) connection from company to product, since these can have an own TCA too, thus making it possible to add starttime, endtime and other values to the MM relation record itself.
The concept is called "intermediate table" and is described here: https://docs.typo3.org/typo3cms/TCAReference/ColumnsConfig/Type/Inline.html#attributes-on-anti-symmetric-intermediate-table
Here is a modified TCA taken from the IRRE tutorial extension. It contains just the necessary settings for the connections and the timestamp field - feel free to add your own fields for companies and products:
$TCA["company"] = Array (
"columns" => Array (
"products" => Array (
"config" => Array (
"type" => "inline",
"foreign_table" => "company_product_intermediate",
"foreign_field" => "company_id",
"foreign_sortby" => "companysort",
"foreign_label" => "product_id",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
);
$TCA["company_product_intermediate"] = Array (
"columns" => Array (
"company_id" => Array (
"config" => Array (
"type" => "select",
"foreign_table" => "company",
"maxitems" => 1,
)
),
"product_id" => Array (
"config" => Array (
"type" => "select",
"foreign_table" => "product",
"maxitems" => 1,
)
),
"companysort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
"productsort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
"timestamp" => Array (
"config" => Array (
"type" => "input",
)
),
),
);
$TCA["product"] = Array (
"columns" => Array (
"companies" => Array (
"config" => Array (
"type" => "inline",
"foreign_table" => "company_product_intermediate",
"foreign_field" => "product_id",
"foreign_sortby" => "productsort",
"foreign_label" => "company_id",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
);

Related

In SuiteCRM how to add custom field in sub panel from relationship table?

I have a module and a sub panel with another module in relationship with it.
As shown in below image-
In the above image its a sub-panel of a module in the relationship,
I have added a column in the relationship table in database.
My requirement is to add that field in this sub-panel list view like shown in image in red rectangle, which is ideally not possible from the studio as per my knowledge.
If anyone has idea to do stuff like this please share.
There may come a time in the development of a custom SuiteCRM module when it would be handy to store additional data in the relationship table between two modules. This is not possible in studio or module builder and is not that straight forward even for an experienced coder unless you have a deep understanding of SuiteCRM underlying architecture.
Step 1 The first thing you need to do is define your new fields in the metadata for the relationship. I will be adding the field in the relationship between a custom module FP_events and Contacts. The relationship fp_events_contacts is a many to many and the subpanel will be displaying the field in the contacts subpanel on the FP_events module.
This file can be found at custom/metadata/fp_events_contactsMetaData.php
In the code below notice that I added a field called date_cancelled with type date to the fields array.
$dictionary["fp_events_contacts"] = array (
'true_relationship_type' => 'many-to-many',
'relationships' =>
array (
'fp_events_contacts' =>
array (
'lhs_module' => 'FP_events',
'lhs_table' => 'fp_events',
'lhs_key' => 'id',
'rhs_module' => 'Contacts',
'rhs_table' => 'contacts',
'rhs_key' => 'id',
'relationship_type' => 'many-to-many',
'join_table' => 'fp_events_contacts_c',
'join_key_lhs' => 'fp_events_contactsfp_events_ida',
'join_key_rhs' => 'fp_events_contactscontacts_idb',
),
),
'table' => 'fp_events_contacts_c',
'fields' =>
array (
0 =>
array (
'name' => 'id',
'type' => 'varchar',
'len' => 36,
),
1 =>
array (
'name' => 'date_modified',
'type' => 'datetime',
),
2 =>
array (
'name' => 'deleted',
'type' => 'bool',
'len' => '1',
'default' => '0',
'required' => true,
),
3 =>
array (
'name' => 'fp_events_contactsfp_events_ida',
'type' => 'varchar',
'len' => 36,
),
4 =>
array (
'name' => 'fp_events_contactscontacts_idb',
'type' => 'varchar',
'len' => 36,
),
5 =>
array (
'name' => 'invite_status',
'type' => 'varchar',
'len'=>'25',
'default'=>'Not Invited',
),
6 =>
array (
'name' => 'accept_status',
'type' => 'varchar',
'len'=>'25',
'default'=>'No Response',
),
7 =>
array (
'name' => 'email_responded',
'type' => 'int',
'len' => '2',
'default' => '0',
),
8 =>
array (
'name' => 'date_cancelled',
'type' => 'date',
),
),
'indices' =>
array (
0 =>
array (
'name' => 'fp_events_contactsspk',
'type' => 'primary',
'fields' =>
array (
0 => 'id',
),
),
1 =>
array (
'name' => 'fp_events_contacts_alt',
'type' => 'alternate_key',
'fields' =>
array (
0 => 'fp_events_contactsfp_events_ida',
1 => 'fp_events_contactscontacts_idb',
),
),
),
);
Once you have added your desired fields to the fields arrays do a quick repair and rebuild from the admin panel of SuiteCRM and then execute the suggested SQL queries this will add the fields to the database table for the relationship. (I double-checked that the fields were added by going into phpmyadmin and looking at the fp_events_contacts_c table.)
Step 2 Your fields are now defined and in the actual database table but your only halfway their if you want your fields to actually be displayed in the subpanel. The next thing you want to do is define your new fields in the vardefs for the relationship. This is done by adding a file in the custom/Extensions folder like so: custom/Extension/modules/Contacts/Ext/Vardefs/CAN_BE_ANY_NAME.php
In this file add the following three definitions for each field your adding. Pay careful attention that all the field names and ids match up between definitions as minor typos here will prevent the fields from showing in the subpanel and can be major pain to spot:
$dictionary['Contact']['fields']['e_date_cancelled'] =
array (
'name' => 'e_date_cancelled',
'rname' => 'id',
'relationship_fields'=>array('id' => 'cancelled_id', 'date_cancelled' => 'event_cancelled'),
'vname' => 'LBL_CONT_ACCEPT_CANCELLED',
'type' => 'relate',
'link' => 'fp_events_contacts',
'link_type' => 'relationship_info',
'join_link_name' => 'fp_events_contacts',
'source' => 'non-db',
'importable' => 'false',
'duplicate_merge'=> 'disabled',
'studio' => false,
);
$dictionary['Contact']['fields']['event_cancelled'] =
array(
'massupdate' => false,
'name' => 'event_cancelled',
'type' => 'date',
'studio' => 'false',
'source' => 'non-db',
'vname' => 'LBL_LIST_ACCEPT_CANCELLED',
'importable' => 'false',
);
$dictionary['Contact']['fields']['cancelled_id'] =
array(
'name' => 'cancelled_id',
'type' => 'varchar',
'source' => 'non-db',
'vname' => 'LBL_LIST_ACCEPT_CANCELLED',
'studio' => array('listview' => false),
);
Step 3 The final thing you need to do is define the fields in the actual layout defs of the subpanel. In this case, that file is located: custom/modules/Contacts/metadata/subpanels/FP_events_subpanel_fp_events_contacts.php
In the code below notice that I add my field event_cancelled (as defined in the step 2 vardefs) to list_fields array and further down in the array I also add e_date_cancelled and cancelled_id and mark their usage as query_only.
$subpanel_layout['list_fields'] = array (
'name' =>
array (
'name' => 'name',
'vname' => 'LBL_LIST_NAME',
'sort_by' => 'last_name',
'sort_order' => 'asc',
'widget_class' => 'SubPanelDetailViewLink',
'module' => 'Contacts',
'width' => '23%',
'default' => true,
),
'account_name' =>
array (
'name' => 'account_name',
'module' => 'Accounts',
'target_record_key' => 'account_id',
'target_module' => 'Accounts',
'widget_class' => 'SubPanelDetailViewLink',
'vname' => 'LBL_LIST_ACCOUNT_NAME',
'width' => '22%',
'sortable' => false,
'default' => true,
),
'phone_work' =>
array (
'name' => 'phone_work',
'vname' => 'LBL_LIST_PHONE',
'width' => '15%',
'default' => true,
),
'email1' =>
array (
'name' => 'email1',
'vname' => 'LBL_LIST_EMAIL',
'widget_class' => 'SubPanelEmailLink',
'width' => '20%',
'sortable' => false,
'default' => true,
),
'event_status_name' =>
array (
'vname' => 'LBL_STATUS',
'width' => '10%',
'sortable' => false,
'default' => true,
),
'event_accept_status' =>
array (
'width' => '10%',
'sortable' => false,
'default' => true,
'vname' => 'LBL_ACCEPT_STATUS',
),
'event_cancelled' =>
array (
'width' => '10%',
'sortable' => false,
'default' => true,
'vname' => 'LBL_ACCEPT_CANCELLED',
),
'edit_button' =>
array (
'vname' => 'LBL_EDIT_BUTTON',
'widget_class' => 'SubPanelEditButton',
'module' => 'Contacts',
'width' => '5%',
'default' => true,
),
'remove_button' =>
array (
'vname' => 'LBL_REMOVE',
'widget_class' => 'SubPanelRemoveButton',
'module' => 'Contacts',
'width' => '5%',
'default' => true,
),
'e_accept_status_fields' =>
array (
'usage' => 'query_only',
),
'event_status_id' =>
array (
'usage' => 'query_only',
),
'e_invite_status_fields' =>
array (
'usage' => 'query_only',
),
'event_invite_id' =>
array (
'usage' => 'query_only',
),
'e_date_cancelled' =>
array (
'usage' => 'query_only',
),
'cancelled_id' =>
array (
'usage' => 'query_only',
),
'first_name' =>
array (
'name' => 'first_name',
'usage' => 'query_only',
),
'last_name' =>
array (
'name' => 'last_name',
'usage' => 'query_only',
),
'salutation' =>
array (
'name' => 'salutation',
'usage' => 'query_only',
),
'account_id' =>
array (
'usage' => 'query_only',
),
);
Also, remember to add the label in this case LBL_ACCEPT_CANCELLED to the custom language strings.
I added it to: custom/Extension/application/Ext/Language/en_us.Advanced OpenEvents.php
$app_strings['LBL_ACCEPT_CANCELLED'] = 'Date Cancelled';
But it may work if added to the mod strings.
Now do another quick repair and rebuild from the admin panel and your custom relationship fields should now be showing up on the subpanel. You will now be able to add data into these fields in your module controller either via queries or through SuiteCRM bean framework.
Note you might have to manually go into the database and add some dummy data into those fields to confirm they are showing (Assuming you have not yet added any data to your new fields).
Cheers!

how to use "filerenameupload" filter in zend framework2?

i add file element in form class with:
$this->add(array(
'type' => 'Zend\Form\Element\File',
'name' => 'logo_file',
'options' => array(
'label' => 'Select your logo image file:',
),
));
then add filter in model for filtering form data. i use "filerenameupload" filter to upload selected file :
$inputFilter = new InputFilter();
$inputFilter->add($factory->createInput(array(
'name' => 'logo_file',
'required' => false,
'filters' => array(
array('name' => 'filerenameupload',
'options'=>array(
//'target' => "./data/logo.png",
'randomize' => true,
)
),
),
)));
and in controller i call setInputFilter, setData and isValid normally. other elements go filter good, but "logo_file" does not be saved in "./data/logo.png".
in fact "filter" function in "Zend\Filter\File\RenameUpload" class does not be executed.
i use this link :
zf2 File Uploding Toturial
Someone's trying to solve this problem?
Have you tried using the full name for the Filter?
array(
'name' => 'Zend\Filter\File\RenameUpload'
)
You also need to make sure you add both the files array and the POST data to the form when validating, example:
$postArr = $request->getPost()->toArray();
$fileArr = $this->params()->fromFiles('logo_file');
$formData = array_merge(
$postArr, // $_POST
array('logo_file' => $fileArr['name']) // $_FILE...
);
$importForm->setData($formData);
Try:
Form.php:
public function addElements(){
$this->add(array(
'name' => 'image',
'attributes' => array(
'type' => 'file',
),
'options' => array(
),
));
FormValidator.php
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
"name" => "image",
"required" => true,
"filters" => array(
array("name" => "StripTags"),
array("name" => "StringTrim"),
array(
"name" => "Zend\Filter\File\RenameUpload",
"options" => array(
"target" => '/home/limonazzo/UPLOADDIR<----------',
"randomize" => true,
"use_upload_name" => true,
"use_upload_extension" => true
)
)
),
"validators" => array(
array(
"name" => "Zend\Validator\File\IsImage",
"break_chain_on_failure" => true,
"options" => array(
),
),
array(
"name" => "Zend\Validator\File\Extension",
"break_chain_on_failure" => true,
"options" => array(
"extension" => "jpg,jpeg,png",
),
),
array(
"name" => "Zend\Validator\File\Size",
"break_chain_on_failure" => true,
"options" => array(
"min" => "1kB",
"max" => "1024kB",
),
),
array(
"name" => "Zend\Validator\File\ImageSize",
"break_chain_on_failure" => true,
"options" => array(
"minWidth" => 10,
"minHeight" => 10,
"maxWidth" => 250,
"maxHeight" => 350,
),
),
),
)));
In controlle.php
$form = new Form();
$formValidator = new FormValidator();
$form->setInputFilter($formValidator->getInputFilter(''));
if ($form->isValid()) {
$data = $form->getData(\Zend\Form\FormInterface::VALUES_AS_ARRAY);
$imgName = $data["image"]["tmp_name"];

getTypoLink_URL not working

i am working on an existing project. I am tyring to use
$params = array(
$this->prefixId.'[cmd]' => 'SINGLE',
$this->prefixId.'[uid]' => intval( $item['uid'] ),
$this->prefixId.'[chash]' => substr( md5( $item['uid'] ), 0, 8 ),
$this->prefixId.'[page]' => $this->GPvars['page'],
);
$link = '<a href="'.str_replace( '&', '&', $this->pi_getPageLink( $this->conf['pidSingle'], '_self', $params ) ).'" target="_self" title="'.$submarks['###SINGLE###'].'">';
$this->pi_getPageLink is not returning anything.
class.tslib_pibase.php is
function pi_getPageLink($id,$target='',$urlParameters=array()) {
return $this->cObj->getTypoLink_URL($id,$urlParameters,$target);
}
That functions need parameters. You should get error messages. Read the API.
$this->cObj->getTypoLink_URL(
123, // ID of the page where you link to
array('test' => 1, 'bar' => 'yes'),
''
);
But i usually use the typolink function. You can use there any typoscript option for typolink:
$this->cObj->stdWrap_typolink(
'',
array(
'returnLast' => 'url',
'parameter' => 123,
'additionalParams' => '&test=1&bar=yes',
)
);
This solution can't work:
$this->cObj->stdWrap_typolink(
'',
array(
'returnLast' => 'url',
'parameter' => 123,
'additionalParams' => '&test=1&bar=yes',
)
);
This one works:
$this->cObj->stdWrap_typolink(
'',
array('typolink' => array(
'returnLast' => 'url',
'parameter' => 123,
'additionalParams' => '&test=1&bar=yes',
)
);

Get data from one table with foreign_table and update to another in TCA

I'm modifying an image upload extension and I'm working on a feature where images can be placed in categories.
Right now the categories are listed in a select field that uses foreign_table to get the categories from a table (called tx_gallery_categories) and when saved the category Id (the value in the option field) is saved to table called tx_gallery_items.
But that column is no longer needed (i was wrong the first time). Depending on what category you choose I want TCA to update a table called tx_gallery_itemsCategory and set the categoryId where itemId is equal to the saved images uid
Here is the TCA (i have removed all other columns beside categoryId) and categoryId is the one I want to move out from this, I think, and in to it's own TCA which is connected to tx_gallery_itemsCategory:
$TCA["tx_gallery_items"] = array (
"ctrl" => $TCA["tx_gallery_items"]["ctrl"],
"interface" => array (
"showRecordFieldList" => "hidden,oid,filename, videoembedcode,caption"
),
"feInterface" => $TCA["tx_gallery_items"]["feInterface"],
"columns" => array (
"categoryId" => Array (
"exclude" => 1,
"label" => "LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items.categories",
"config" => Array (
"type" => "select",
"foreign_table" => "tx_gallery_categories",
// "foreign_table_where" => " true"
// "itemsProcFunc" => "tx_gallery_getImageCategories->getCategories"
// 'default' => '123'
)
),
),
"types" => array (
"0" => array("showitem" => "hidden, oid, filename, categoryId, videoembedcode, caption, linkpid")
)
);
$TCA["tx_gallery_categories"] = array (
"ctrl" => $TCA["tx_gallery_categories"]["ctrl"],
"interface" => array (
"showRecordFieldList" => "categoryTitle"
),
"feInterface" => $TCA["tx_gallery_categories"]["feInterface"],
"columns" => array (
"categoryTitle" => Array (
"exclude" => 0,
"label" => "LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items.categories",
"config" => Array (
"type" => "text",
"cols" => "30",
"rows" => "5",
)
)
),
"types" => array (
"0" => array("showitem" => "categoryTitle")
)
);
But instead of it working like that I want to save the images uid from tx_gallery_items to another table called tx_gallery_itemsCategory which is a many to many table between tx_gallery_items and tx_gallery_categories
Here are the tables:
tx_gallery_items:
uid | pid | ... (and many more but only uid is relevant)
432 | 34 | ...
tx_gallery_itemsCategory:
id | itemId | categoryId
1 | 432 | 1
tx_gallery_categories:
uid | pid | categoryTitle
1 | 34 | example category
And here is the ext_tables.php
$TCA["tx_gallery_items"] = array (
"ctrl" => array (
'title' => 'LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items',
'label' => 'filename',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'sortby' => 'sorting',
'delete' => 'deleted',
'enablecolumns' => array (
'disabled' => 'hidden',
),
'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php',
'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_gallery_items.gif',
),
"feInterface" => array (
"fe_admin_fieldList" => "hidden, oid, filename, category, videoembedcode, caption, linkpid, categoryId",
)
);
$TCA["tx_gallery_categories"] = array (
"ctrl" => array (
'title' => 'LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items',
'label' => 'categoryTitle',
'tstamp' => 'tstamp',
'sortby' => 'sorting',
'delete' => 'deleted',
// 'enablecolumns' => array (
// 'disabled' => 'hidden',
// ),
'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php',
'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_gallery_items.gif',
),
// "feInterface" => array (
// "fe_admin_fieldList" => "uid, pid, categoryTitle, categoryDescription, tstamp, sorting, deleted, hidden, categorySlug",
// )
);
So my question is (i think) how can I get the uid from the current image the user is editing and save it to another table.
This is my first try with TCA and I'm very confused on how all this is connected.
I hope that anyone knows this better than me :)
Thanks.
There is the hook concept implemented in the tcemain component. There is one called processDatamap_postProcessFieldArray which is invoked when any record is saved in the backend. Thus, you can check whether it's "yours" and do your other queries or whatever you want to change.
There is an example of how to use this feature. Although it is pretty old, it should still be working that way.

How to updated nested array

How I can modify nested array e.g.
`array (
'_id' => new MongoId("4e3a81376155a9d439000000"),
'name' => 'Umar',
'password' => 'rose',
'email' => 'umar#ibm.com',
'experience' =>
array (
0 =>
array (
'company' => 'ibm',
'from' => '2005',
'to' => '2007',
),
1 =>
array (
'company' => 'sun',
'from' => '2007',
'to' => '2009',
),
2 =>
array (
'company' => 'oracle',
'from' => '2009',
'to' => 'still',
),
),
)
`
Now i want to update company sun from value existing value is 2007 I want to change with 2006. I am using PHP.
Would you please help.
Best Regards,
Umar
Quite simply:
$yourArray["experience"][1]["from"] = 2006;