Add first item to collection on create (Slider with first Slide)

Often it helps editors to directly add items to a collection to show how it should be used, or it makes sense to directly add some items since the empty-collection is not usefull.

An common example is a slider-content that should have the first slide already attached directly on create.

To achive this create a class that handles the afterNodeCreate-signal checke the type of the created node and acts as needed.

<?php
namespace Vendor\Site\CR\Signals\;

use TYPO3\Flow\Annotations as Flow;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
use TYPO3\TYPO3CR\Domain\Service\NodeTypeManager;
use TYPO3\TYPO3CR\Domain\Service\NodeServiceInterface;

/**
 * @Flow\Scope("singleton")
 */
class CreateDefaultContent
{

	/**
	 * @Flow\Inject
	 * @var NodeTypeManager
	 */
	protected $nodeTypeManager;

	/**
	 * @Flow\Inject
	 * @var NodeServiceInterface
	 */
	protected $nodeService;
    
	/**
	 * Callback to handle the afterNodeCreate signal
	 * @param NodeServiceInterface $node
	 */
	public function handleAfterNodeCreateSignal (NodeInterface $node) 
	{
	     
        // add a slide to new slider nodes
        if ($node->getNodeType()->isOfType('Vendor.Site:Content.Slider')) {
            $node->createNode(
                $this->nodeService->generateUniqueNodeName($node->getPath()),
                $this->nodeTypeManager->getNodeType('Vendor.Site:Content.Slide')
            );
        }
    }
}

After that add a Classes\Vendor\Site\Package.php file to register the callback-method for the signal.

<?php
namespace Vendor\Site;

use TYPO3\Flow\Package\Package as BasePackage;
use TYPO3\TYPO3CR\Domain\Model\Node;
use Vendor\Site\CR\Signals\CreateDefaultContent;

class Package extends BasePackage {

    public function boot(\TYPO3\Flow\Core\Bootstrap $bootstrap)
    {
        $dispatcher = $bootstrap->getSignalSlotDispatcher();
        $dispatcher->connect(
            Node::class, 'afterNodeCreate',
            CreateDefaultContent::class, 'handleAfterNodeCreateSignal'
        );
    }
}

NOTE: It is possible to use named/autocreated child nodes for this but this will lead to trouble as soon as node:repair is trying to fix the html-structure.

3 Likes

Why is this leading to trouble? I have used that approach before and it seems to work just fine.

'My.Namespace:TabItem':
  superTypes:
    'TYPO3.Neos:Content': TRUE
    'TYPO3.Neos:ContentCollection': TRUE
  ui:
    label: 'Tab'`

'My.Namespace:Tabs':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  ui:
    label: 'Tabs'
    inlineEditable: TRUE
  constraints:
    nodeTypes:
      'My.Namespace:TabItem': TRUE
      '*': FALSE
  childNodes:
    tab1:
      type: 'My.Namespace:TabItem'

Is there something I might have done incorrectly?

If you do a node:repair the autocreated child nodes will be moved before the other nodes … so you risk uncontrolled node reordering.

That’s a bug, isn’t it?

Please add this to the NEOS How to’s.

That would be great =)

It’s more an unspecified behavior. Another problem would be that if you later decide to delete the autocreated item it will appear again after node:repair.

Sure … I see the FAQ as an incubator for how-tos

I thought you can’t delete autocreated nodes?

Hmm … might be … but that would also be an unexpected behavior. I would definitely avoid mixing of autocreated and normal child nodes for such a purpose.