Search code examples
typo3typo3-9.xdatahandler

Move existing pages into newly created pages with TYPO3 DataHandler


I am using the DataHandler to create and move pages like in this snippet. While new pages are created fine, existing subpages are not moved into their newly created parents.

This creates the new page but does not move the existing page

$data = [
    'pages' => [ 
        'NEW_IT' => [
            'pid' => 1,
            'hidden' => false,
            'title' => 'IT',
        ],
        591 => [
            // this is not set
            'pid' => 'NEW_IT', 
            // but this is set
            'title' => 'I am a child of IT', 
        ],
    ]
];

I tried ['pages'][591]['move'] = 'NEW_IT' but also to no avail.

I also tried '591' instead of 591, dataHandler->reverseOrder = true and dataHandler->copyTree = true.

dataHandler->errorLog is empty.

In contrary, this works (new page into new page)

$data = [
    'pages' => [ 
        'NEW_IT' => [
            'pid' => 1,
            'hidden' => false,
            'title' => 'IT',
        ],
        'NEW_IT_SUB' => [
            'pid' => 'NEW_IT',
        ],
    ]
];

Also I wonder which IDs (NEW<any string> vs. NEW<base64> etc.) are acceptable as I did not find anything in the documentation and the examples use different styles. The "must be unique" is obvious. But I don't get why some people generate UUIDs there.

References

EDIT: I opened a forge ticket: https://forge.typo3.org/issues/90939


Solution

  • I have checked the code / DataHandler in v8/v9 and master. The corresponding logic in the DataHandler has not changed for that.

    I have created a test case and xdebugged through it, also i was pretty sure after looking into the code, what happens. But have done this to validate that "it is working the way i think the code tells" - although it is not the way you expected. And I'm too. Remembering that I had such an issue last year through a migration script, but did not digged deeper into it (because of time), i changed it and made this as loops.

    Creating page => retrieving the replaced id => using it for the other data commands.

    The datahandler loops through each record for a table in the provided dataset array.

    foreach ($this->datamap[$table] as $id => $incomingFieldArray) { ... }
    

    First it prepares some stuff, and calling registered processDatamap_preProcessFieldArray hooks, it checks the given $id

    // Is it a new record? (Then Id is a string)
    if (!MathUtility::canBeInterpretedAsInteger($id)) { ... } else { ... }
    

    If the id is not an integer or an integer string, it executed the true-branch, otherwise the false-branch. So long, so good.

    The TRUE-Branch handles creating a new record (page, tt_content, ...), adding the replacement for the provided NEWxxx as substituion and so on.

    It also checks, if a 'pid' field is in the record, and if it contains with NEW. If it is so, it replaces NEWxxx with the uid of the previously created record.

    On the otherhand, if $id is not a integer or a integer string, it assumes it is an existing record. (FALSE-Branch). On this branch there is no checking for 'pid', if it contains NEW and looking up for replacement.

    But .. why is there no error ? If it did not replace it, it should crash or someting like that ? - Yes, that is what we would assume - at least for that.

    'pid' is always ignored in appling to the record ( see method fillInFieldArray() )

    switch ($field) {
        case 'uid':
        case 'pid':
             // Nothing happens, already set
             break;
      ...
    }
    

    and so .. as long as you do not provide further fields/values in the second page array ( that with the integer id and the pid with NEW from the initial), it has nothing to do. Nothing to do is not an error - and so, it do nothing and even do not notify anything about it.

    Is it a bug ? Don't know, personally I would say yes. But maybe this should be created as an issue, and eventually discussed with the core developer/other contributers.

    Maybe there were/are reasons WHY it only do this one run.

    Either the documentation should be changed to make clear, that 'pid' replacement only works, id $id => [] is also a new / playholder id .. or you have to do it in 2 rounds.

    Or .. put as as feature/bug to the issue tracker, and let's discuss it. And maybe giv it a try to implement it in the FALSE/existing record branch too. But let's heare some other opionons about it.

    If others thing this should be also be done for the existing records in the same round, I would take the time tommorrow/at the weekend to provide an patch for it / the issue. (Would be fun to fight with the datahandler ).