Typo3 8.7 itemsProcFunc do not modifies existing items - php

I'm new to Typo3. I want to add a custom content element with a specifc select field within this content element.
For the custom content element, I modified the pageTSConfig with
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig and added my element. This is working. In order to store my content value, I added the "ext_tables.sql" file with
#
# Table structure for table 'tt_content'
#
CREATE TABLE tt_content (
tx_spk_shopware_category varchar(20) NULL
);
and finally I override the TCA configuration for tt_content and this is not working. I see the new content element with my custom type with my items within the config, but I cannot modify / add any items in the class referenced in itemsProcFunc.
tt_content.php:
<?php declare(strict_types=1);
defined('TYPO3_MODE') || die();
// static TypoScript
(static function () {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
array(
'LLL:EXT:spk_shopware/Resources/Private/Language/Tca.xlf:spk_shopware_category.wizard.title',
'spk_shopware_category',
'EXT:spk_shopware/Resources/Public/Icons/ContentElements/spk_shopware_category.gif'
),
'CType',
'spk_shopware'
);
$temporaryColumn = array(
'tx_spk_shopware_category' => array (
'exclude' => 1,
'label' => 'LLL:EXT:spk_shopware/Resources/Private/Language/Tca.xlf:spk_shopware_category.title',
'config' => array (
'type' => 'select',
'itemsProcFunc' => SPK\Shopware\Hook\ShopwareCategorySelect::class . '->listAvailableShopwareCategories',
'items' => array(
array('test 1', '8'),
array('test 2', '10'),
),
'maxitems' => 1,
'minitems' => 1,
'required' => true,
)
)
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
'tt_content',
$temporaryColumn
);
})();
// Configure the default backend fields for the content element
$GLOBALS['TCA']['tt_content']['types']['spk_shopware_category'] = array(
'showitem' => '
--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xml:palette.general;general,
tx_spk_shopware_category
');
CategorySelect.php
<?php
namespace SPK\Shopware\Hook;
class ShopwareCategorySelect
{
public function listAvailableShopwareCategories(&$config)
{
$config['items'][] = ["Tim", 0];
$config['items'][] = ["Tom", 1];
$config['items'][] = ["Jerry", 2];
array_push($config['items'], ["as", 1]);
return $config;
}
}
I see the custom element and new select field, but only with the test elements in the config. I don't know what I'm missing.

Seems, TYPO3 does not find your class. Please check if you have provided appropriate information:
via composer.json, section "autoload":
{
"name": "vendorname/my-extension",
"type": "typo3-cms-extension",
// ...
"autoload": {
"psr-4": {
"Vendorname\\MyExtension\\": "Classes/"
}
}
}
...or via ext_emconf.php, section "autoload":
<?php
$EM_CONF[$_EXTKEY] = [
'title' => 'My Extension',
// ...
'autoload' => [
'psr-4' => [
'Vendorname\\MyExtension\\' => 'Classes'
]
]
];

You do not really need to return anything. You just want to modify the items of your column. Try the following:
public function listAvailableShopwareCategories(&$config)
{
$config['items'][] = ["Tim", 0];
$config['items'][] = ["Tom", 1];
$config['items'][] = ["Jerry", 2];
$this->getItems = $config['items'];
}
You modify the &$config by adding the items just before it is rendered on your TCA. That's the reason why your PHP file is under the Hooks folder. It just hooks the items between the response :)

Related

TYPO3 unable to fetch data with dataProcessing in template of custom content element

I created a custom content element with a custom field.
I added the custom field like this in the overrides of tt_content.php
$elements = [
'myCustomField' => [
'exclude' => true,
'label' => 'The label of my field',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'tx_vendor_domain_model_myfavoritepictures,
],
],
],
];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tt_content', $elements);
This field is included in the TCA of my custom content element, it stores the relations to chosen records which contain pictures.
The fluidtemplate of my custom content elements contains only a debug-viewhelper.
What I am trying to achieve is to fetch the pictures of the records, which are chosen in myCustomField. For that, I tried to use the "DatabaseQueryProcessor" as described in the official TYPO3 documentation: https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/ContentObjects/Fluidtemplate/DataProcessing/DatabaseQueryProcessor.html
ce_mycustomcontentelement < lib.customContentElement
ce_mycustomcontentelement {
templateName = CeMyCustomContentElement
dataProcessing.10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
dataProcessing.10 {
if.isTrue.field = myCustomField
table = tx_vendor_domain_model_myfavoritepictures
as = myFavoritePictures
// recursively process the files in the records with the FilesProcessor
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10 {
references.fieldName = picture
}
}
}
}
However, for the field "myFavoritePictures" which is defined in the dataProcessing Property, I am getting an empty array from the debug-viewhelper in my fluidtemplate of my custom content element. I am guessing, that i didn't cofigured the dataProcessing porperty correctly but unfortunately I don't know what might me wrong.

TYPO3 Custom Element colorpicker

I'm new to TYPO3 (first project) and I have some understanding issues of the creation of a custom element with a colorpicker. In this project I already have created a few elements but I only use predetermined fields for the backend input. For the element I need next I need the user to choose a color. I haven't found a fitting existing element. My setup that doesn't work is in the TCA/Overrides/tt_content.php file and looks like this.
$GLOBALS['TCA']['tt_content']['item_0']=array();
$GLOBALS['TCA']['tt_content']['item_0']['label']='Color';
$GLOBALS['TCA']['tt_content']['item_0']['config']=array();
$GLOBALS['TCA']['tt_content']['item_0']['config']['type']='input';
$GLOBALS['TCA']['tt_content']['item_0']['config']['renderType']='colorpicker';
$GLOBALS['TCA']['tt_content']['item_0']['config']['size']=10;
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Title,
subheader;Background,
header_link;Target,
item_0;Color,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
The item_0 was a try to create a colorpicker but it doesn't seem to work. Do I need something different in a different file? The first few lines I added to define my field. Is there a better way to do this?
All other files in my custom extension work (since all other custom elements work fine). The only difference is, as said, the need of a way to choose a color in the new one.
Just for a clearer look here the other files
setup.txt:
lib.contentElement {
templateRootPaths {
100 = EXT:wostyle/Resources/Private/Template
}
}
tt_content {
wo_mitem < lib.contentElement
wo_mitem {
templateName = MItem
}
}
tt_content.php
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
array(
'WO_Item (ItemBox, Text only)',
'wo_mitem',
'content-image'
),
'CType',
'wostyle'
);
$GLOBALS['TCA']['tt_content']['item_0']=array();
$GLOBALS['TCA']['tt_content']['item_0']['label']='Farbe';
$GLOBALS['TCA']['tt_content']['item_0']['config']=array();
$GLOBALS['TCA']['tt_content']['item_0']['config']['type']='input';
$GLOBALS['TCA']['tt_content']['item_0']['config']['renderType']='colorpicker';
$GLOBALS['TCA']['tt_content']['item_0']['config']['size']=10;
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Bezeichnung,
subheader;Chemische Bezeichnung,
header_link;Zielseite,
item_0;Farbe,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
typo.ts
mod.wizards.newContentElement.wizardItems.wo_extra {
header = WO Elemente
after = common
elements {
wo_mitem {
iconIdentifier = content-image
title = WO_Item (ItemBox, Text only)
description = Ein Produktfeld mit Text
tt_content_defValues {
CType = wo_mitem
}
}
}
show := addToList(wo_mitem)
}
MItem.html
<div class="item-text">
<f:link.typolink parameter="{data.header_link}">
<div class="item-front">
<f:if condition="{data.subheader}!=''">
<f:then>
<div class="item-bg">
<f:format.html>{data.subheader}</f:format.html>
</div>
</f:then>
</f:if>
<div class="item-title">
<f:format.html>{data.header}</f:format.html>
</div>
</div>
<div class="item-back">
<f:format.html>{data.bodytext}</f:format.html>
</div>
</f:link.typolink>
</div>
<f:debug>{data}</f:debug>
EDIT: I use typo3 8.7.8
I did not check your whole code but I have a working color-picker on a field ...
you're close but an error that pops up right away is that your item should be placed under ['columns'] ...
$GLOBALS['TCA']['tt_content']['columns']['item_0']=array();
next you are missing the refference to the wizard !! (you should adopt the annotation with square brackets which shows much more the structure)
this should be stored in Configuration/TCA/Overrides/tt_content.php: (when you override existing fields, otherwise you have a dedicated code for the element)
<?php
/***************
* Modify the tt_content TCA
*/
$tca = [
'columns' => [
'item_0' => [
'label' => 'Color',
'config' => [
'type' => 'input',
'size' => 10,
'eval' => 'trim',
'default' => '#ffffff',
'wizards' => [
'colorChoice' => [
'type' => 'colorbox',
'title' => 'LLL:EXT:lang/locallang_wizards:colorpicker_title',
'module' => [
'name' => 'wizard_colorpicker'
],
'dim' => '20x20',
'JSopenParams' => 'height=600,width=380,status=0,menubar=0,scrollbars=1',
],
],
],
],
],
];
$GLOBALS['TCA']['tt_content'] = array_replace_recursive($GLOBALS['TCA']['tt_content'], $tca);
With the help of webMan and some internet searches I could adopt my code a little.
I added the file "ext_tables.sql" with the content
CREATE TABLE tt_content (
item_0 varchar(10) DEFAULT '' NOT NULL,
);
And changed the tt_content.php in TCA/Overrides to:
$temporaryColumns = Array(
"item_0" => Array(
'label' => 'Color',
'config' => Array(
'type' => 'input',
'renderType' => 'colorpicker',
'size' => 10
)
)
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tt_content',$temporaryColumns);
$GLOBALS['TCA']['tt_content']['types']['wo_mitem'] = array(
'showitem' => '--palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
header;Bezeichnung,
subheader;Chemische Bezeichnung,
header_link;Zielseite,
item_0;Farbe,
bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css]
');
There are still a view things missing in compare to webMans code but at least this is the first working version I have so i figured i show it since my question is answered:).

drupal 8 programmatically create node can only succeeded once

I'v created a new module in Drupal 8, it is just a hello world example.
the code just like the following
class FirstController{
public function content(){
return array(
'#type' => 'markup',
'#markup' => t('G\'day.............'),
);
// <------I added the new node code here
}
}
and I added the following code to the content() function to create a node .
but I found that it can only create the node once, and after that no matter how many time I refresh the module page it won't be creating any more new node again.
use \Drupal\node\Entity\Node;
use \Drupal\file\Entity\File;
// Create file object from remote URL.
$data = file_get_contents('https://www.drupal.org/files/druplicon.small_.png');
$file = file_save_data($data, 'public://druplicon.png', FILE_EXISTS_REPLACE);
// Create node object with attached file.
$node = Node::create([
'type' => 'article',
'title' => 'Druplicon test',
'field_image' => [
'target_id' => $file->id(),
'alt' => 'Hello world',
'title' => 'Goodbye world'
],
]);
$node->save();
any thing I'm doing wrong here?
You forgot about caching :) Your output is just cached, and that's why your code is called only once (to be more precise, not once, but until cache is valid). Take a look here: Render API and here: Cacheability of render arrays.
To disable caching for current page request you may use the following code:
\Drupal::service('page_cache_kill_switch')->trigger();
So, your controller method may look like the following:
public function content() {
// Create file object from remote URL.
$data = file_get_contents('https://www.drupal.org/files/druplicon.small_.png');
/** #var FileInterface $file */
$file = file_save_data($data, 'public://druplicon.png', FILE_EXISTS_RENAME);
// Create node object with attached file.
$node = Node::create([
'type' => 'article',
'title' => 'Druplicon test',
'field_image' => [
'target_id' => $file->id(),
'alt' => 'Hello world',
'title' => 'Goodbye world'
],
]);
$node->save();
\Drupal::service('page_cache_kill_switch')->trigger();
return array(
'#markup' => 'Something ' . rand(),
);
}

How to inject the Doctrine ObjectManager into form element

I'm working on my custom User module, which basically uses ZfcUser as the foundation. Since every application is different and requires different meta information about users I want this to be easily configurable using a config array.
In my module's global config file I define the custom form fields and in the Module's onBootstrap I extend the ZfcUser registration form using the init event of ZfcUser\Form\Register. So in short I want to do something like this:
$sharedEvents->attach('ZfcUser\Form\Register',
'init',
function($e) use ($sm)
{
/* #var $form \ZfcUser\Form\Register */
$form = $e->getTarget();
// Get relevant config
$config = $sm->get('config');
if ( array_key_exists('redev_user', $config) && is_array($config['redev_user']) )
{
if ( array_key_exists('custom_fields', $config['redev_user']) && is_array($config['redev_user']['custom_fields']) )
{
foreach ($config['redev_user']['custom_fields'] as $curCustomField)
{
$form->add($curCustomField);
}
}
}
[...]
In my config file I then define the custom form fields like this:
<?php
return array(
'redev_user' => array(
'custom_fields' => array(
// Custom fields which will be added to the registration form
array(
'name' => 'firstname',
'type' => 'text',
'options' => array(
'label' => 'First name',
),
),
I do the same thing for the validators; they are being defined in the config file and attached to the form elements in the onBootstrap.
This all works nice and dandy, except when I need a Doctrine form element. In my specific case I would like to use a DoctrineModule\Form\Element\ObjectSelect for the country selectbox. In my config this would look like this:
array(
'name' => 'country',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'label' => 'Country',
//'object_manager' => $sm->get('Doctrine\ORM\EntityManager'),
'target_class' => 'RedevUser\Entity\Country',
'property' => 'countryname',
'is_method' => false,
'find_method' => array(
'name' => 'findBy',
'params' => array(
'criteria' => array(),
'orderBy' => array('countryname' => 'ASC'),
),
),
),
),
Note the commented out line for the object_manager. The ObjectSelect element obviously needs the ObjectManager. The question is how do I inject the ObjectManager while rendering the form based on the config.
I was thinking to render the form element myself and then check if it's an instance of some interface or base class of DoctrineModule\Form\Element. However it turns out there is no such base class or interface. The only thing those elements have in common is that they have a getProxy. Right now my code in onBootstrap looks like this:
foreach ($config['redev_user']['custom_fields'] as $curCustomField)
{
$formElemFactory = $form->getFormFactory();
$elem = $formElemFactory->createElement($curCustomField);
if ($elem instanceof \DoctrineModule\Form\Element\ObjectSelect)
{
// Inject ObjectManager
$elem->getProxy()->setObjectmanager($sm->get('Doctrine\ORM\EntityManager'));
}
$form->add($elem);
}
But I don't really want to check for the different Doctrine form element types. Also it seems a bit dirty to do it like this. Any opinions or ideas of how to do this better/cleaner?

Adding a custom filter to views in Drupal 7

im using Drupal 7 and I want to add a new filter in views.
I have a custom table "clicks" with two fields; nid and clicks_left.
The filter should just contain a checkbox "Only display nodes with clicks left". So the filter should join node and clicks on nid..
I have read like thousands of pages of custom filters but can't get it to work =)
Please, could someone show me a working example so I understand?
I have come so far that the filter is displayed under filters but what do I need to add to do the join and get the checkbox? The relevant code below:
FILE clicks_views.inc:
function clicks_views_data() {
$data = array();
$data['clicks']['clicks_filter'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'field' => 'clicks_left',
'handler' => 'clicks_handler_filter',
),
);
return $data;
}
FILE clicks_handler_filter.inc:
<?php
class clicks_handler_filter extends views_handler_filter {
???
};
I know both functions are wrong ;)
Ok, I've found a solution. For anyone who needs it:
In clicks.module
function clicks_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'clicks') . '/includes'
);
}
In clicks.views.inc
function clicks_views_handlers() {
return array(
'info' => array(
'path' => drupal_get_path('module', 'clicks') . '/includes', // path to view files
),
'handlers' => array(
// register our custom filter, with the class/file name and parent class
'clicks_handler_filter' => array(
'parent' => 'views_handler_filter',
)
),
);
}
function clicks_views_data() {
$data = array();
if(module_exists('clicks')) {
$data['node']['clicks'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'handler' => 'clicks_handler_filter',
),
);
}
return $data;
}
In clicks_handler_filter.inc
class clicks_handler_filter extends views_handler_filter {
function admin_summary() { }
function operator_form() { }
function query() {
$table = $this->ensure_my_table();
$join = new views_join();
$join->construct('clicks', $this->table_alias, 'nid', 'nid');
$this->query->ensure_table('clicks', $this->relationship, $join);
$this->query->add_where($this->options['group'], "clicks.clicks_left", 0, ">");
}
}
This gives me a possibility to add a filter "clicks" that if enabled hides all results that doesn't have clicks left (clicks_left > 0)
Actually, if your values in your tables clicks are numeric you don't need to create your own handler, you can use the default from Views views_handler_filter_numeric.
You can see all handlers that already exists in the Views handlers.

Categories