Extbase mapOnProperty with inline field - typo3

I have an extension with an extbase model, which I want to extend. Works fine for all fields, except an "inline" field. When I map that inline field, I do not receive all child elements, but only one child element with the counter as uid.
Example: The inline field "description" has three children (uid = 17, uid = 18, uid = 19), so the field tx_firstextension_domain_model_job.description contains the number 3. In the frontend, I have an ObjectStorage, containing exactly one Description model (uid = 3)
Here is my TypoScript:
config.tx_extbase {
objects.Foo\FirstExtension\Domain\Model\Job.className = Bar\SecondExtension\Domain\Model\Job
persistence.classes.Bar\SecondExtension\Domain\Model\Job.mapping {
table = tx_firstextension_domain_model_job
columns {
description.mapOnProperty = description
anyotherfield.mapOnProperty = anyotherfield
onemorefield.mapOnProperty = onemorefield
}
}
}
SOLUTION
My problem was a wrong configuration option. Correct is tableName, but I used table. Here is the corrected - end even more simple - snippet:
config.tx_extbase {
objects.Foo\FirstExtension\Domain\Model\Job.className = Bar\SecondExtension\Domain\Model\Job
persistence.classes.Bar\SecondExtension\Domain\Model\Job.mapping {
tableName = tx_firstextension_domain_model_job
}
}

There seems to be a misconfiguration in your Job-Models configuration. Please check the following:
Is inside the model (Job.php) the property description configured as ObjectStorage (including getter and setter function + annotations correctly) and does the property be instantiated as ObjectStorage in the __construct function?
Is the field correctly configured as type "inline" in the TCA configuration file Configuration/TCA/tx_secondextension_domain_model_job.php
Probably you have to extend the TCA of the first extension in order to make inline work when extending other extensions. Then you maybe have to add the field description to Configuration/TCA/Overrides/tx_firstextension_domain_model_job.php but I'm not sure if this is really necessary...

Related

Retrieve content element field from within a plugin template?

I am modifying the template of a plugin, and I want to retrieve a field from the content element.
Using f:debug I see the only data available is from the plugin itself, and none from the content element.
Is there any way I can perhaps insert the field I need in the plugin settings?
eg. something like:
plugin.tx_plugin.settings {
contentUid = TEXT
contentUid.field = uid
}
The best way I can think of to do this is with a custom ViewHelper. Something like:
namespace MyVendor\MyExtension\ViewHelpers;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class ContentUidViewHelper extends AbstractViewHelper
{
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
return $configurationManager->getContentObject()->data['uid'];
}
}
In your Fluid template:
<mynamespace:contentUid />
This will get the uid of the content element, but you can get any field this way. Just change the key of the data array to the field you need.
In the corresponding method (like the listAction or showAction) of the controller you can get the data of the content element in the following way:
$contentObject = $this->configurationManager->getContentObject();
$this->view->assign('contentObjectData', $contentObject->data);
As far as I know, you can't get to that data using typoscript, but I've never needed it anyway since I've been using the above code in the controller.
settings do not have stdWrap-type per default, but only string. So you can not use cObjects as values.
For one (or a few) settings, you could do the stdWrap-processing in your method/class yourself:
$settingsAsTypoScriptArray = $this->objectManager->get(TypoScriptService::class)->convertPlainArrayToTypoScriptArray($this->settings);
$contentObj = $this->configurationManager->getContentObject();
if ($contentObj === null) {
$contentObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
}
// now override the values in the settings array with the processed value
$contentUid = (int)$contentObj->stdWrap($settingsAsTypoScriptArray['contentUid'], $settingsAsTypoScriptArray['contentUid.']);
If you wanna have many settings to be stdWraped, have a look into EXT:news. Georg implemented an interesting concept via useStdWrap configuration.

TYPO3 8.7.13 - getArguments() return no response

\Templates\Snippets\Search.html
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="snippet_highlight_syntax"
pluginName="feshs"
name="searchSnippets"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" property="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
SnippetsController.php
public function searchAction()
{
$arguments = $this->request->getArguments();
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($arguments);
}
ajax.js
$("#snippetSearchForm").submit(function (event) {
event.preventDefault();
var form = $(this);
var action = form.attr("action"),
method = form.attr("method"),
data = form.serialize();
$.ajax({
url: action,
type: method,
data: data,
cache: false
}).done(function (data) {
console.log(data);
}).fail(function () {
( "div.tx-feshs" ).replaceWith("errorMessage");
}).always(function () {
});
});
Request URL
index.php?id=148&type=5513&tx_snippet_highlight_syntax_feshs[action]=search&tx_snippet_highlight_syntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
I can't solve this problem with getArguments(). The response and console.log are (empty). Seems like I'm missing something but I can't pinpoint where :/
You have a few common errors in your code and most of them has already been mentioned here, but please allow me to sum up.
Extension key/name
First, a lot of people confuses extension name with extension key. The directory name of your extension is your extension key, in this case snippet_highlight_syntax. The extension key is used all over TYPO3 as the unique identifier of your extension. With Extbase a new convention did come along called extension name to satisfy PSR2 coding convention and is primarily used in Extbase context. The extension name is a upper camel case edition of your extension key.
ExtbaseFluidBook: CodingGuidelines - It´s a bid old but still valid
The name of the extension in UpperCamelCase. For example, if the extension-key is blog_example, then this part of the classname is BlogExample.
Extension key: snippet_highlight_syntax
Extension name: SnippetHighlightSyntax
Be aware of what the TYPO3/Extbase framework asks for, key or name - it will help you a lot.
Plugin name
You have also declared a plugin named feshs. According to the DocBlock documentation of both \TYPO3\CMS\Extbase\Utility\ExtensionUtility::(configure|register)Plugin() methods it should, as with the extension name, be in upper camel case format like Feshs. It´s not well documented and I do not think it has any negative impacted on your application jet but now you knows and has a change to future proof your application by correcting it.
/**
* ...
*
* #param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
* #param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
* #param array $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
* #param array $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
* #param string $pluginType either \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_PLUGIN (default) or \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
* #throws \InvalidArgumentException
*/
public static function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = [], $pluginType = self::PLUGIN_TYPE_PLUGIN)
Plugin signature
Together with your extension name it will form a plugin signature called snippethighlightsyntax_feshs. This signature is the valued stored in the tt_content database table as list_type or ctype depending of the plugin configuration.
The plugin signature is further used in TypoScript and GET/POST arguments prefixed with tx_. In your case tx_snippethighlightsyntax_feshs.
Fluid & Extbase forms
In your form snippet you have declared a element <f:form:textfield /> with the property tag. The property tag is only used together with the object and objectName tags on the <f:form /> element and is used to bind values to this objects properties (autofill, validation result etc.).
See \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper::initializeArguments.
Name of Object Property. If used in conjunction with <f:form object="...">, "name" and "value" properties will be ignored.
In your case you should properly just use name in stead of property.
Your updated form should look something like below:
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="SnippetHighlightSyntax"
pluginName="Feshs"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" name="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
Controller arguments
You should declare your arguments as controller arguments.
/**
* #param string $searchWords
*/
public function searchAction(string $searchWords = null)
{
if (is_string($searchWords)) {
// TODO: Do something here...
}
}
Note how I have given the argument a default value. This should suppress the error Required argument "searchWords" is not set for... you are getting.
This was a long write up. Hopes it helps your or some others.
Happy coding
$this->request->getArguments() will only return field value arguments that are prefixed with the extensions / plugins identifier like tx_anything_pi1[anything]
Please checkout if the "name"-tag of the fields is correct. Maybe those tags are wrong because you are reffering to a "property" of an object in your textfield but there is no object bound to your f:form tag.
Since the response should at least return the HTML of an empty debug, maybe something is wrong with your action. Can you call it in the browser?
First of all use name attribute instead of property in <f:form.textfield> tag.
Then you need to register argument as follows
public function searchAction(string $searchWords)
Furthermore PHP docblock must contain the parameter as #param string $searchWords. After clearing all caches in the Install Tool you should get your arguments.
Assumed your extension-key (=foldername) is "snippet_highlight_syntax" the parameter for URLs is usually like this:
tx_snippethighlightsyntax_feshs
That means all underscores of the extension-key are removed.
Probably it's possible to make it different, but that's not standard.
Therefore $this->request->getArguments() never returns anything.
You've to adjust the parameters in the url like this:
index.php?id=148&type=5513&tx_snippethighlightsyntax_feshs[action]=search&tx_snippethighlightsyntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
In the TypoScript-Object-Browser you should find your plugin with that name:
plugin.tx_snippethighlightsyntax_feshs
After many tries, I've sent the extension to test on another computer and it's working.
I've cleared all the caches, disabled/enabled, and so on. Seems like my environment is at fault.
Thanks to all of you for the help !

TYPO3 Extension: 'Unknown column in field list' error

Basically: Every time I add a new class/model with the extension_builder and then want to create a record of that class I get the following error message:
2: SQL error: 'Unknown column 'edited' in 'field list''
(tx_icingaconfgen_domain_model_checkperiod:NEW5a27f9da8a41d636846075)
The interesting thing is: "edited" is NOT a property of that class, but the property of other classes in that extension. I've searched through the TCA of the class that throws the error and also the MySql table itself, but the field "edited" is indeed not part of that class. What's going on here?
Edit: What I find interesting is the fact that when I add a column "edited" to MySql table manually, the record can be created. But in no way I'm using this property in my Model. Why does it require a MySql column of that name then?
Without seeing the code I can only guess whats going on. Surely the field is requiered when a record is persisted. So it is possible that you referenced it in your TCA. If not in the columns maybe in the ctrl section:
'ctrl' => [
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
...
],
These fields are updated automatically if a recods is changed or created. There are more of those fields. So check your ctrl section.
It is also possible that you map another property (possibly even of another class) to that database field in your TypoScript like this:
plugin.tx_myextension {
persistence {
classes {
MyVendor\MyExtension\Domain\Model\Person {
mapping {
tableName = tt_address
recordType = \MyVendor\MyExtension\Domain\Model\Person
columns {
birthday.mapOnProperty = dateOfBirth
}
}
}
}
}
}
Example taken from here.
As it turned out the culprit was actually this line of code in the ext_localconf.php:
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['extkey'] = 'Cjk\\Icingaconfgen\\Hook\\EvalHook';
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass']['extkey'] = 'Cjk\\Icingaconfgen\\Hook\\EvalHook';
It's a hook that I've implemented into my extension that just marks if a record has been edited in the BE or not. I actually use this Hook that whenever a record is edited changes the propety edited from 0 to 1. This is intended of course, but the class checkperiod doesn't have the property 'edited'. But since the hook for the Datamapper works with every record that is changed or created it also tries to change 'edited' in classes that don't have this property. A simple if condition in the Hook itself, if the key 'edited' of the $fieldArray is NULL solved my problem.
class EvalHook {
function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$pObj) {
if($status == "update" && $table != 'tx_icingaconfgen_domain_model_checkperiod'){
$fieldArray[edited] = 1;
}
elseif($status != "update" && $table != 'tx_icingaconfgen_domain_model_checkperiod){
$fieldArray[edited] = 0;
}
}
}

Fetch all the values of specific property in aem using queryBuilder

I am having scenario in which i want to fetch all the values of a property under a specific path in AEM using QueryBuilder api.
This property can have single or multivalued.
Any help will be appreciated!!
Example that can help you. is below as it is just for illustration written in simple JSP scriptlets
<%
Iterator<Resource> iter = resourceResolver.findResources("/jcr:root/content/geometrixx-outdoors//element(*, nt:unstructured)[(#imageRotate = '0' or #imageRotate = '1')]","xpath");
while (iter.hasNext()) {
Resource child = iter.next();
out.println("</br>"+child.getPath());
Node node = child.adaptTo(Node.class);
Property nProp = node.getProperty("imageRotate");
if(nProp.isMultiple()) // This condition checks for properties whose type is String[](String array)
{
Value[] values = nProp.getValues();
out.println(" :: This is a multi valued property ::");
for (Value v : values) {
out.println("</br>"+"Property Name = "+nProp.getName()+" ; Property Value= "+v.getString());
}
}
else if(!nProp.getDefinition().isMultiple()){
out.println("</br>"+"Property Name = "+nProp.getName()+" ; Property Value= "+nProp.getString());
}
}
%>
Here i have used the Iterator<Resource> iter = resourceResolver.findResources(query,"xpath"); which can give you the query results which matches the imageRotate property under /content/geometrixx-outdoors/ path which consists combination of single and multivalued as shown in below screenshot.
There is no direct way to fetch the properties using query builder api. I would suggest you to create a servlet resource, which requires a path and property name.
Fetch the jcr node using the given path via QueryBuilder. Then, you need to loop through the results to check the property of the nodes. You can access the multiple property values, once you have a node.

SharePoint - Set custom publishing page layout custom field programatically

I have a custom publishing page content type, based on the Publishing Article Page content type. On this content type, I have a custom field named "PageContentCategory". In my code to create new pages, I tried this:
PublishingPage newPublishingPage = this.currentPublishingWeb.GetPublishingPages().Add(pageName, newPageSelectedLayout);
if (pageContent.IsEmpty())
{
pageContent = Properties.Resources.EAWorldArticleHandler_CreateNewArticlePage_DefaultPageContent;
}
newPublishingPage.ListItem[new Guid("{93496B35-7EC3-4132-B0D0-3BDC5606F5EF}")] = pageContentCategory;
newPublishingPage.ListItem[FieldId.PublishingPageContent] = pageContent;
newPublishingPage.Title = pageTitle;
newPublishingPage.Update();
I have also tried to set it by the field name:
PublishingPage newPublishingPage = this.currentPublishingWeb.GetPublishingPages().Add(pageName, newPageSelectedLayout);
if (pageContent.IsEmpty())
{
pageContent = Properties.Resources.EAWorldArticleHandler_CreateNewArticlePage_DefaultPageContent;
}
newPublishingPage.ListItem["PageContentCategory"] = pageContentCategory;
newPublishingPage.ListItem[FieldId.PublishingPageContent] = pageContent;
newPublishingPage.Title = pageTitle;
newPublishingPage.Update();
Both of these methods throw an error. Is there any way for me to set my custom field's value in code like this?
Try calling the Update method on newPublishingPage.Listitem not on newPublishingPage itself.
Like this:
newPublishingPage.ListItem["PageContentCategory"] = pageContentCategory;
newPublishingPage.ListItem.Update();
and then you maybe also need some of these lines, depending in the configuration of your page library
newPublishingPage.Checkin();
newPublishingPage.Publish();
newPublishingPage.Approve();
So, the solution to my problem was that I had to programmatically add the content type to the pages list instead of letting it be added automatically the first time a page with that content type was added. Apparently if you let SharePoint automatically add the content type to the pages list then it somehow doesn't get bound properly. So adding the content type first solved my problem.