flowpack / flowpack.nodetemplates Goto Github PK
View Code? Open in Web Editor NEWNeos CMS package that auto creates nodes based on a declarative template
License: GNU General Public License v3.0
Neos CMS package that auto creates nodes based on a declarative template
License: GNU General Public License v3.0
At the moment, the uriPathSegment property of a document is always generated by the TemplatingDocumentTitleNodeCreationHandler; thus, it's not possible to set it via a NodeTemplate. We should only generate it, if it is not set by the NodeTemplate.
Currently if you use a malformed expression, or the expression yields an error its hard to debug, in which property path the exception was caused.
ideally an exception would look like:
expression in template path: `childNodes.bar.properties.someProperty` threw Error: ...
it a bit tedious but a simple implementation could look like:
try {
$propertyValue = $this->eelEvaluationService->evaluateEelExpression($propertyValue, $context);
} catch (\Exception $exception) {
throw new \Exception(sprintf('Property "%s": "%s" could not be evaluated.', $propertyName, $propertyValue), 1684257493838, $exception);
}
The issue became present again: #20
there are now actually two handlers we have to fight:
as suggested by @dimaip once we must implement positioning, as we cannot possibly augment any possible future processor, that changes the title. #21 (review)
sorting will be possible as bugfix via: neos/neos-ui#3511
Currently since we use
if (preg_match(\Neos\Eel\Package::EelExpressionRecognizer, $name)) {
$name = $this->eelEvaluationService->evaluateEelExpression($name, $context);
}
this will not qualify as an eel expression and never be evaluated and thus set as literal string property: (can you spot why? :P)
properties:
foo: "${'hello + data.bar}"
this is just a simple case but in more complex scenarios its quite easy to forget to close the quotes of a string, write a malformed object or forget the ending eel brace.
we should fail in any case.
As its most likely not wanted to write the literal string which starts with ${
... anywhere. And even if one wants to do it one can still use a string inside eel.
In V1 you could have for example a node creation dialog to select an asset from the media module. This will be a string id in data.image
.
Once you try to assign it to a property, it will fail, because the validator (correctly) says that the id is not of type ImageInterface
Property "image" in NodeType "Your.Vendor:Image" | PropertyIgnoredException(Because value `"4b5f90cb-6f42-4edd-91d9-6a0f4f0d6ddb"` is not assignable to property type "Neos\Media\Domain\Model\ImageInterface"., 1685958105644)
We should find a solution for this problem that will continue to work with 9.0
Given the following configuration:
ui:
label: Author
icon: icon-user
creationDialog:
elements:
title: ~
firstName:
type: string
ui:
label: 'Vorname'
editor: 'Neos.Neos/Inspector/Editors/TextFieldEditor'
lastName:
type: string
ui:
label: 'Nachname'
editor: 'Neos.Neos/Inspector/Editors/TextFieldEditor'
options:
template:
properties:
title: '${data.lastName + ", " + data.firstName}'
the title of the generated page is not set.
When building a more complex template and a loop, you might encounter the situation, when you only want to set this property on iteration 1 or something and otherwise return null
, thinking it will be ignored.
Currently the behaviour with null might not be 100% obvious.
template:
properties:
someSimplePropertyWithDefaultValue: null
someReferencePropery: null
someReferencesProperty: [null]
in the first case someSimplePropertyWithDefaultValue
will be set to null (see $node->getProperties()
) (also see somewhat related discussion about properties without default value or not previous value beeing skipped: neos/neos-development-collection#4292)
in the latter cases with the reference properties, the null value will be (rightfully) ignored, but because the setProperty
will guard this:
the question i asked myself, if it would be generally expected, that when null is returned, that the setProperty
operation will be skipped for the property.
This would be helpful for cases, where you dont want to hardcode the default value. But this change might be breaking in unexpected ways...
At the moment, prefilling from internal properties (for example _hiddenAfterDateTime
, _hidden
, etc) doesn't work.
Property mapping and reference resolving
this way we can assert the package is working correctly and it hopefully makes migrating to 9.0 easier
It would be great, if one could define in withContext
an additional global context, which is merged with the other values like triggeringNode
options:
template:
withContext:
fooReferenceNode: '${q(triggeringNode).find("#" + data.fooReference).get(0)}'
this way frequently computed values can be easily defined once at the top and dont need to be recomputed which might speed up performance marginally but mainly increases readability
The property of conditions is currently named "when" which is a bit confusing as there was no "when" before in Neos. Is there reason for that?
@theilm: What do you think about renaming it to "if" which would be consistent with the naming in fusion.
Or even to "@if" to denote - like in Fusion - that this is a meta property.
An then - maybe adopt the complete fusion notation and allow multiple if statements with @if.<identifier>: <condition>
Not sure, if this an error in this package or in the UI.
The media button in creation dialog do not work, it throws a js error.
The media modul is opening.
Nothing visually, but in console I get an js error.
index.js:137 Uncaught TypeError: n.props.renderSecondaryInspector is not a function
at AssetEditor.n.handleChooseFromMedia (index.js:137)
at Object.Ja (react-dom.production.min.js:26)
at Object.invokeGuardedCallback (react-dom.production.min.js:25)
at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.production.min.js:25)
at Za (react-dom.production.min.js:30)
at cb (react-dom.production.min.js:32)
at gb (react-dom.production.min.js:32)
at Array.forEach (<anonymous>)
at ab (react-dom.production.min.js:31)
at lb (react-dom.production.min.js:34)
Neos: v3.3.13
UI: v1.1.2
Flowpack.NodeTemplates: <= 1.0
At the moment, not all editors are available in the creation dialog.
(Might be outdated, as I had no time to reproduce this with the newest version. My Version was 1.1.1. Edit: I tested it with 1.3.1 and the issue still exists).
It seems to me that the node template config does not work (does not insert nodes automatically) if its parent is a configured childNode, meaning, the user did not insert it itself but it was generated as configured under the yaml key childNodes (of some higher parent in the hierarchy).
To put it another way: To me it looks like there is some hook that is not called when nodes are inserted by "the framework" instead of the user.
due to the fact, that the are implemented in another TemplatingDocumentTitleNodeCreationHandler they currently bypass the core logic.
We should avoid the need for this TemplatingDocumentTitleNodeCreationHandler
(i have a prototype already locally and will create a pr soonish)
when creating a more complex node template, to create multiple pages and content elements, it can be helpful to take the current node subtree as reference. For this case a command controller would be great.
flow nodeTemplate:fromSubtree 136a646c-b2d5-4475-8e24-b25727aa7913 --workspaceName=live
Your.NodeType:
options:
template:
childNodes:
page0:
name: page-0
type: Foo.Bar:Page
properties:
title: 'my page'
uriPathSegment: my-page
# someReference -> Reference of NodeTypes (Neos.Neos:Document) with value Node(13f5e86b-7b0e-4a7f-9a8a-af6bdf1c1913)
childNodes:
page0:
name: page-0
type: Foo.Bar:Pag
properties: ...
childNodes:
mainContentCollection:
name: main
childNodes: ...
I just realized that there is a new release of this package (1.0.0 => 1.1.0) and it states βWith this release, the templating of document titles and node paths is also possible.β but there is no documentation of this new feature whatsoever
This patter doesnt work currently
properties:
image:
type: ImageInterface
ui:
showInCreationDialog: true
options:
template:
properties:
imageCaption: '${data.image.copyrightNotice}'
as data.image
is not converted. The dump looks like:
array(2)
'__identity' => 4567890,
'__type' => 'ImageVariant'
related: #61
version: 2.x
Hi, I have a content element which supertypes Neos.Neos:ContentCollection.
Therefore I don't have a named childNode of type ContentCollection.
I tried something like this, to add childNodes directly to my node, but it did not work.
'Vendor.XYGrid:Row':
superTypes:
'Neos.Neos:Content': true
'Neos.Neos:ContentCollection': true
ui:
...
options:
template:
childNodes:
column1:
type: 'Vendor.XYGrid:Column'
column2:
type: 'Vendor.XYGrid:Column'
it currently takes about a minute. I experimented with composer cache but that alone doesnt make much of a difference
If the template is malformed, all created nodes should be deleted, or better: A template should be first evaluated and expanded to a big array and then only rendered into the node tree not in the same run.
Separating the processes would make the code also easier testable, and the template less coupled the the old content repository implementation.
Many exceptions are currently thrown like:
throw new PropertyIgnoredException(
sprintf(
'Because property is not declared in NodeType. Got value `%s`.',
json_encode($propertyValue)
),
1685869035209
);
Property "nonDeclaredProperty" in NodeType "Flowpack.NodeTemplates:Content.SomeExceptions" | PropertyIgnoredException(Because property is not declared in NodeType. Got value
"hi"
., 1685869035209)
This provides not the best output for editors. A fully readable text would be better than starting with Because
With NodeTemplates version 1.2 I've created the possibility to create template sites where you can add content elements to have a fast quick start (e.g. for blog posts).
For this, I've created following mixin
'Base.Templates:Mixin.CreationDialog':
ui:
creationDialog:
elements:
templateNodeIdentifier:
type: reference
ui:
label: Template
editorOptions:
nodeTypes: ['Base.Templates:Mixin.Template']
options:
template:
childNodes:
mainContentCollection:
when: '${data.templateNodeIdentifier}'
name: main
options:
childNodesToCopy: "${q(node).find('#' + data.templateNodeIdentifier).children('main').children().get()}"
And following Package.php
<?php
namespace Base\Templates;
use Base\Templates\Service\ChildNodeCopyService;
use Flowpack\NodeTemplates\Template;
use Neos\Flow\Core\Bootstrap;
use Neos\Flow\Package\Package as BasePackage;
/**
* The Node Templates Magic Package
*/
class Package extends BasePackage
{
/**
* @param Bootstrap $bootstrap The current bootstrap
* @return void
*/
public function boot(Bootstrap $bootstrap)
{
$dispatcher = $bootstrap->getSignalSlotDispatcher();
$dispatcher->connect(
Template::class,
"nodeTemplateApplied",
ChildNodeCopyService::class,
"copyChildNodesAfterTemplateApplication"
);
}
}
The ChildNodeCopyService.php
looks like that
<?php
namespace Base\Templates\Service;
use Flowpack\NodeTemplates\Service\EelEvaluationService;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Eel\Package as EelPackage;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Service\NodeOperations;
/**
*/
class ChildNodeCopyService
{
/**
* @var EelEvaluationService
* @Flow\Inject
*/
protected $eelEvaluationService;
/**
* @var NodeOperations
* @Flow\Inject
*/
protected $nodeOperations;
/**
* @param NodeInterface $node
* @param array $context
* @param array $options
* @return void
*/
public function copyChildNodesAfterTemplateApplication(
NodeInterface $node,
array $context,
array $options
): void {
// Copy child nodes from template
if (
isset($options["childNodesToCopy"]) &&
preg_match(
EelPackage::EelExpressionRecognizer,
$options["childNodesToCopy"]
)
) {
$childNodes = $this->eelEvaluationService->evaluateEelExpression(
$options["childNodesToCopy"],
$context
);
/** @var NodeInterface $childNode */
foreach ($childNodes as $childNode) {
$this->nodeOperations->copy($childNode, $node, "into");
}
}
}
}
With the new version, it is not possible to create this helpful feature. Should we create an API for that, to make this possible?
While I think that NodeTemplates is a great package, I find the according templates a little cumbersome to configure due to the fact that there can be deep nesting.
I think it would be a good idea to create a setting "development mode" for the package and then add an additional inspector tab to Document nodes, displaying the node structure in the way that you could copy it to the Node Type definition.
This way, you could create a node that suits your needs, copy the definition and adjust (e.g. pre-defined property values).
What do you think? We might be willing to (help) funding this, so an estimate would be great.
When upgrading from 2.0.0 to 2.0.1, one template configuration stops working. Extract:
options:
template:
childNodes:
content:
name: 'content'
childNodes:
text:
type: 'KaufmannDigital.Nova.NodeTypes.Text:Atom.Text'
Apparently the exception is thrown at Classes/Domain/NodeCreation/NodeCreationService.php L97+
if (!$parentNode->getNodeType()->allowsChildNodeType($nodeType)) {
$caughtExceptions->add(
CaughtException::fromException(new \RuntimeException(sprintf('Node type "%s" is not allowed for child nodes of type %s', $template->getType()->getValue(), $parentNode->getNodeType()->getName()), 1686417627173))
);
continue;
}
The exception that's coming up:
RuntimeException(Node type "KaufmannDigital.Nova.NodeTypes.Text:Atom.Text" is not allowed for child nodes of type Neos.Neos:ContentCollection, 1686417627173)
I am not 100% certain yet but I think the issue is coming up because in that template we are inserting nodes into generic content collections, however the constraint is checked via allowsChildNodeType
in NodeType, which however is not considering special constraints defined for those collections. The constraints are defined exeplicitely:
childNodes:
content:
type: 'Neos.Neos:ContentCollection'
constraints:
nodeTypes:
'KaufmannDigital.Nova.NodeTypes.Text:Atom.Text': TRUE
Hi, I miss the feature where you can adjust the maximum child nodes that could appear.
It is not possible to overwrite an existing Configuration and setting child nodes to null
.
./flow nodeTypes:show Agency.Base:Content.Bla --path options.template
returns:
childNodes:
mainContentCollection:
name: content
childNodes:
headline:
type: 'Vendor.Website:Content.Bla'
text: null
buttonArea: null
Currently it seems that I cannot create a field with type array:
salutation:
type: 'Sitegeist.PaperTiger:Field.RadioButtons'
properties:
name: 'salutation'
label: 'Anrede'
isRequired: true
options: [label: 'Frau', value: 'Frau'], [label: 'Herr', value: 'Herr']
How a RadioButtons
element looks in the node properties:
{
"isRequired": true,
"customErrorMessageEnabled": false,
"name": "salutation",
"label": "Anrede",
"options": {
"0": {
"label": "Frau",
"value": "Frau"
},
"1": {
"label": "Herr",
"value": "Herr"
}
}
}
Error message:
Configuration "childNodes.fields.childNodes.fieldset.childNodes.salutation.properties.options" | RuntimeException(Template configuration properties can only hold int|float|string|bool|null. Property "options" has type "array", 1685725310730)
Is this concious limitation or not possible technically?
If a property has a defaultValue
set, this value doesn't get set in the creation dialog
The value of an DateTime field in creation dialog can't be given to the inspector field without cast to an DateTime object.
Error message during creation of a new node (without cast):
Exception in line 259 of /MyProject/Packages/Libraries/neos/utility-objecthandling/Classes/ObjectAccess.php: Argument 1 passed to Neos\ContentRepository\Domain\Model\Node_Original::setHiddenAfterDateTime() must be an instance of DateTime or null, string given, called in /MyProject/Packages/Libraries/neos/utility-objecthandling/Classes/ObjectAccess.php on line 259
(...)
creationDialog:
elements:
_hiddenAfterDateTime:
type: DateTime
ui:
label: i18n
editor: 'Neos.Neos/Inspector/Editors/DateTimeEditor'
editorOptions:
format: 'd.m.Y'
(...)
options:
template:
properties:
_hiddenAfterDateTime: "${data._hiddenAfterDateTime}"
The date set in creation dialog is also set in corresponding inspector field
"Argument 1 passed to .... must be an instance of DateTime or null, string given."
Requires cast to DateTime object:
options:
template:
properties:
_hiddenAfterDateTime: "${Date.create(data._hiddenAfterDateTime)}"
Neos: 4.0.6
NodeTemplates: 1.0.0
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.