-2

I'm trying to run DataHandler commands from multiple contexts (Frontend, Backend, etc.). From what I've read and tried, this has to be done within a Synfony command for it to work properly. Only then, within the command, code snippets like these can be run:

Bootstrap::initializeBackendAuthentication();
$data = [...]
$dataHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
$dataHandler->start($data, []);
$dataHandler->process_datamap();

And it's the _cli_ back-end user the one running these DataHandler commands.

I've created my Synfony command according to the docs. It's registered and I can call it like this and it works as expected:

$ vendor/bin/typo3 myext:rundatahandler

My question is: How can I run this within a PHP class? I can't find it anywere in the docs or online. I only find it for Synfony Controller classes, which behave differently and have different inputs and attributes than those of TYPO3.

Thanks a lot in advance!

DidacC
  • 93
  • 2
  • 13
  • What do you mean by "class"? What kind of class? Where would this call be executed? The example shown [here](https://symfony.com/doc/current/console/command_in_controller.html) would work just about anywhere. Where did you try that approach, and how did it fail? – yivi Apr 05 '22 at 05:33
  • Also, more often than not, if you find yourself wanting to execute the command from different contexts, you should extract its functionality to a service which then you could call either from the console command or from wherever you need it. – yivi Apr 05 '22 at 05:37
  • @yivi As the OP said, calling commands from the Symfony Controller doesn't suit him. That's why I suggested using `Process`, why did you find this solution not worthy? – emrdev Apr 05 '22 at 05:52
  • @HarviDent If you meant the downvote, it wasn't mine. But in any case, I don't think much of the solution because: it was suggested elsewhere many times, it's a bad approach in any case since extracting the functionality to another service would be more intelligent, and more importantly because without understanding _why_ the other approach does not work, is just simply giving advice blindly (which, as I just mentioned, is not only _bad_ advice, but repeated advice). – yivi Apr 05 '22 at 05:54
  • Hey, thanks a lot for the answers! @yivi ., by "class" I meant, e.g. an Extbase Controller class. By extracting its functionality you mean using this core library: https://docs.typo3.org/m/typo3/reference-coreapi/10.4/en-us/ApiOverview/Services/Introduction/Index.html? – DidacC Apr 05 '22 at 08:03
  • And what happens when you try to use the approach in the docs in your Extbase Controller class? Do you get an error? Why doesn't it work? – yivi Apr 05 '22 at 08:12
  • @yivi The thing is that I don't know how to call the Synfony console command from an Extbase Controller class. The examples I find online, like this one: https://symfony.com/doc/current/console/command_in_controller.html Use a method with that KernelInterface parameter to call it, which I don't know how to implement for the Extbase controller class. – DidacC Apr 05 '22 at 08:36
  • Have you tried injecting the `KernelInterface` in your controllers? That's still a symfony application. – yivi Apr 05 '22 at 08:38
  • Thanks a lot guys but in the end I went with @HarviDent's approach and it went out successfully. – DidacC Apr 05 '22 at 22:09

1 Answers1

3

You can use The Process Component to run commands in your class.

Installation

composer require symfony/process

Use in your PHP Class

use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class YouClass{

    public function someAction(){
        $process = new Process(['vendor/bin/typo3', 'myext:rundatahandler']);
        // set the working directory to the root of the project
        $process->setWorkingDirectory(getcwd() . "/../");
        $process->run();
    }
}

Note: Also, if your class does not have access to the vendor folder, then you must require the vendor/autoload.php

require 'vendor/autoload.php';
emrdev
  • 2,155
  • 3
  • 9
  • 15
  • 1
    Thanks for the answer! In the end I followed your approach and created a Symfony Command class that accepts both `$cmd` and/or `$data` arrays as JSON strings and, upon successfully running the DataHandler call, returns the `$copyMappingArray_merged` also as a JSON string, to be able to get the UIDs of copied records. Then I created a static utility method to which you pass the `$cmd` and/or `$data` arrays that serializes them and calls the Symfony command synchronously. It also fetches and deserializes the `$copyMappingArray_merged`. Works like a charm! – DidacC Apr 05 '22 at 22:08