Discussion:
[TYPO3-english] Command Controller: I can't execute a command that uses class repositories of my extension
christian ewigfrost
2017-11-07 09:30:13 UTC
Permalink
Yesterday i finally got my Typo3 Scheduler working the way i want. Mostly it was the implementation of the CommandController into my extension that was a little bit "problematic".
Now i have another question regarding the Scheduler and the CommandController specifically. I have an Action i have implemented in the controller of a class of my extension. This Action i'd like to use automated in the scheduler.

Now, what the function does is simply generating a specific file i need to use in another application. The function gets the repsitory of the class "Host" and then finds all objects of it. Then it just uses the properties of each object to generate the beforementioned files. It does the same with the class "services".
In the frontend through the Action the code works perfectly and generates the files, but in the CommandController, executed automatically through the Scheduler it simply doesn't work.
Is there a missunderstanding on my side? Can't i access each class repository via a command or rather: "Are the repositories only accessable via an Action?"
Or is there another error in my thought?

Here is the code, it's the way it is implemented in the Action of the class controller AND in the COmmandController:

public function simpleCommand()
{
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class);
$hosts = $apprep->findAll();

$objectManager2 = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$apprep2 = $objectManager2->get(\Cjk\Icingaconfgen\Domain\Repository\ServicesRepository::class);
$services = $apprep2->findAll();

foreach($hosts as $host)
{
$name = $host->getUid();
$address = $host->getIpv4();
$file = '/etc/icinga2/conf.d/hosts/' . $name . '.conf';
$code_a = 'object Host "';
$code_b = '" {
import "generic-host"
address = "';
$code_c = '"
vars.notification["mail"] = {
groups = [ "icingaadmins" ]
}
}';
$fp = fopen("{$file}", 'wb');
fwrite($fp, $code_a . $name . $code_b . $address . $code_c);
fclose($fp);
mkdir('/etc/icinga2/conf.d/hosts/' . $name);

foreach($services as $service)
{
if($service->getHost() == $name)
{
$name = $host->getUid();
$chkcmd = 'http';
$file = '/etc/icinga2/conf.d/hosts/'.$name.'/' . $name . '-service.conf';
$code_a = 'object Service "';
$code_b = '" {
import "generic-service"
host_name = "';
$code_c = '"
check_command = "http"
}';
$fp = fopen("{$file}", 'wb');
fwrite($fp, $code_a . $name.'-service'. $code_b . $name . $code_c);
fclose($fp);
}
}

exec('sudo /etc/init.d/icinga2 restart');

}

}
Mikel
2017-11-07 10:41:11 UTC
Permalink
You need to implement an „execute“ method into your task.
public function execute()

See documentation:
The only method that must be implemented is the execute() method which is expected to perform the task logic.

To go for sure that the task is performed, you can var_dump something and trigger the task in the scheduler by clicking the „play“ button.
christian ewigfrost
2017-11-07 11:01:25 UTC
Permalink
The task runs well enough, i tried this with creating a dummy file with some summy text in it with trying to access the repositories. It worked (even without execute()). But it seems i cannot access the repositories from the Command Controller.
Mikel
2017-11-07 12:18:56 UTC
Permalink
Try to fetch a single record with findByUid instead of getting all with findAll. If you get a result, your repository has no records storage uid. You can set it global in TypoScript or you can change your repository settings.
Just to go for sure: Rename your method to execute and let your class extend the AbstractTask of TYPO3.

Does that solve the problem?

Mikel
christian ewigfrost
2017-11-07 12:50:26 UTC
Permalink
Quote: Mikel wrote on Tue, 07 November 2017 13:18
----------------------------------------------------
Post by Mikel
Try to fetch a single record with findByUid instead of getting all with findAll. If you get a result, your repository has no records storage uid. You can set it global in TypoScript or you can change your repository settings.
Just to go for sure: Rename your method to execute and let your class extend the AbstractTask of TYPO3.
Does that solve the problem?
Mikel
----------------------------------------------------

Same as before. I even tried to inject the repositories in the class of the CommandController:

/**
* hostRepository
*
* @var \Cjk\Icingaconfgen\Domain\Repository\HostRepository
* @inject
*/
protected $hostRepository;

/**
* servicesRepository
*
* @var \Cjk\Icingaconfgen\Domain\Repository\ServicesRepository
* @inject
*/
protected $servicesRepository;

And then i just tried to access the repository in the function:

$hosts = $this->hostRepository->findAll();


$services = $this->servicesRepository->findAll();

To be clear: The task seems to be run in the Scheduler without problems, but the code doesn't generate the files i want, whereas as a frontend Action it produces them without flaw. I didn't try your execute() suggestion yet.
christian ewigfrost
2017-11-07 12:57:36 UTC
Permalink
BTW: I used that Stackoverflow post as a reference:

https://stackoverflow.com/questions/23068053/in-an-extbase-extension-how-to-access-the-persistence-layer-from-a-scheduler-ta/23077743#23077743

The problem is: I don't understand where to put the line "module.tx_yourext.persistence < plugin.tx_yourext.persistence" since i don't have this setup.txt in the specific directory, but rather a setup.ts. Adding the line to the setup.ts doesn't change anything.
christian ewigfrost
2017-11-07 13:04:29 UTC
Permalink
..Also the part about: "The TypoScript needs to be present in the root page of your website for backend modules/CommandControllers to use them. I suggest you add the stuff to myext/Configuration/TypoScript/setup.txt and add the static template of your ext to the root page."

..Is something that i can't warp my head around. How do i do this and why should i do this?
Mikel
2017-11-07 13:18:17 UTC
Permalink
This TypoScrips won’t help, as you don’t have a module nor a plugin (module = backend module, plugin = frontend plugin).

But I don’t get it right now. Can you please focus? :-)

As far as I know, DependencyInjection does not work in the tasks. You have to build the instances in the constructor of your task.

Can you do the following:
1. Register your task in ext_localconf.php (see code below)
2. Extend the AbstractTask
3. Place the execute task
4. Build your instance of your repo directly within this method (or in the constructor, but without using dependency injection)
5. Fetch a single record by an existing UID
6. var_dump the result and trigger the task manually via the scheduler

Examples (this code is tested and works in 8.7.8)

1.

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\Conversion\ConversionWebsite\Tasks\TestTask::class] = array(
'extension' => $_EXTKEY,
'title' => 'Foobar Test'
);
2. 3. 4. 5.

class TestTask extends AbstractTask
{

public function execute() {
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$apprep = $objectManager->get(\Conversion\ConversionWebsite\Domain\Repository\CustomerRepository::class);

DebuggerUtility::var_dump($apprep->findByUid(1));

}

}
christian ewigfrost
2017-11-07 13:31:18 UTC
Permalink
One thing i'm confused about:

I already registered the CommandController in the ext_localconf.php like this:

if (TYPO3_MODE === 'BE') {

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'Cjk\\Icingaconfgen\\Command\\SimpleCommandController';

}

So i need to additionally add the task? Is this for the execute function? Sry for these stupid questions, this is my 3rd day working with the scheduler and i'm very very new to Typo3, so pls don't hold it against me.^^
Mikel
2017-11-07 14:02:12 UTC
Permalink
Post by christian ewigfrost
if (TYPO3_MODE === 'BE') {
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'Cjk\\Icingaconfgen\\Command\\SimpleCommandController';
}
The commandController is something else. It makes commands executable from the shell (console / command line / however you wanna call it).
Post by christian ewigfrost
So i need to additionally add the task? Is this for the execute function? Sry for these stupid questions, this is my 3rd day working with the scheduler and i'm very very new to Typo3, so pls don't hold it against me.^^
No problem. You did not choose the easy way to learn TYPO3 by developing a task :-)
I will try to explain as simple as possible:
TYPO3 has a scheduler system, which is invoked by a system’s cronjob. Therefor you need to setup a system cronjob calling the TYPO3 dispatcher,
The dispatcher triggers to execute all registered tasks in the scheduler (if they are scheduled).
So ONE system cronjob triggers the TYPO3 scheduler to execute all scheduled tasks.

You can also use a commandController and trigger that command directly from your cronjob. But this has nothing to do with the scheduler then...
christian ewigfrost
2017-11-07 14:08:18 UTC
Permalink
OK, i tried to do what you told me:

I registered the task in the ext_localconf.php:

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\Cjk\Icingaconfgen\Tasks\TestTask::class] = array(
'extension' => $_EXTKEY,
'title' => 'Foobar Test'
);

I created a TestTask.php file in Classes/Command/ directory:

<?php

namespace Cjk\Icingaconfgen\Tasks;

class TestTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask
{

public function execute() {
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');

$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class)

DebuggerUtility::var_dump($apprep->findByUid(1));

}

}

But when i want to save the task Foobar Test i get an error:

Oops, an error occurred!
syntax error, unexpected 'DebuggerUtility' (T_STRING)
Mikel
2017-11-07 14:18:49 UTC
Permalink
Post by christian ewigfrost
Oops, an error occurred!
syntax error, unexpected 'DebuggerUtility' (T_STRING)
Take the full namespace (or take a use statement at the beggining of your class):
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($apprep->findByUid(1));
christian ewigfrost
2017-11-07 14:25:00 UTC
Permalink
Quote: Mikel wrote on Tue, 07 November 2017 15:18
----------------------------------------------------
Post by Mikel
Post by christian ewigfrost
Oops, an error occurred!
syntax error, unexpected 'DebuggerUtility' (T_STRING)
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($apprep->findByUid(1));
----------------------------------------------------

Another error:

Oops, an error occurred!
syntax error, unexpected '\' (T_NS_SEPARATOR)
Mikel
2017-11-07 14:34:25 UTC
Permalink
Post by christian ewigfrost
Oops, an error occurred!
syntax error, unexpected '\' (T_NS_SEPARATOR)
Please show your complete code.
christian ewigfrost
2017-11-07 14:36:01 UTC
Permalink
It works now, it was my fault...

But: I get an error when executing the saved task:


Execution of task "Foobar Test ()" failed with the following message: Task failed to execute successfully. Class: Cjk\Icingaconfgen\Tasks\TestTask, UID: 5
christian ewigfrost
2017-11-07 14:37:03 UTC
Permalink
Here my TestTask.php:

<?php

namespace Cjk\Icingaconfgen\Tasks;

class TestTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask
{

public function execute() {
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');

$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class);

\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($apprep->findByUid(1));

}

}
christian ewigfrost
2017-11-07 14:49:15 UTC
Permalink
Quote: christian ewigfrost (ewigfrost) wrote on Tue, 07 November 2017 15:37
----------------------------------------------------
Post by christian ewigfrost
<?php
namespace Cjk\Icingaconfgen\Tasks;
class TestTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask
{
public function execute() {
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($apprep->findByUid(1));
}
}
----------------------------------------------------

But above the error i get a var dump window with NULL.
Mikel
2017-11-07 15:05:09 UTC
Permalink
Stupid question: do you have an existing record with uid = 1 in your database?
Mikel
2017-11-07 15:02:52 UTC
Permalink
The execute method needs a return statement.
Add return TRUE; add the end of your method.
christian ewigfrost
2017-11-07 15:08:17 UTC
Permalink
Quote: Mikel wrote on Tue, 07 November 2017 16:02
----------------------------------------------------
Post by Mikel
The execute method needs a return statement.
Add return TRUE; add the end of your method.
----------------------------------------------------

Thanks... It works.

But the var dump returns NULL.
christian ewigfrost
2017-11-07 15:14:30 UTC
Permalink
Quote: christian ewigfrost (ewigfrost) wrote on Tue, 07 November 2017 16:08
----------------------------------------------------
Post by christian ewigfrost
Quote: Mikel wrote on Tue, 07 November 2017 16:02
----------------------------------------------------
Post by Mikel
The execute method needs a return statement.
Add return TRUE; add the end of your method.
----------------------------------------------------
Thanks... It works.
But the var dump returns NULL.
----------------------------------------------------

Sry, i realized that the first host object has the uid 128... With that i get the object returned in var dump. So it works flawlessly.
christian ewigfrost
2017-11-07 15:32:41 UTC
Permalink
Quote: christian ewigfrost (ewigfrost) wrote on Tue, 07 November 2017 16:14
----------------------------------------------------
Post by christian ewigfrost
Quote: christian ewigfrost (ewigfrost) wrote on Tue, 07 November 2017 16:08
----------------------------------------------------
Post by christian ewigfrost
Quote: Mikel wrote on Tue, 07 November 2017 16:02
----------------------------------------------------
Post by Mikel
The execute method needs a return statement.
Add return TRUE; add the end of your method.
----------------------------------------------------
Thanks... It works.
But the var dump returns NULL.
----------------------------------------------------
Sry, i realized that the first host object has the uid 128... With that i get the object returned in var dump. So it works flawlessly.
----------------------------------------------------

But really thanks... So far at least i can access the repository but my biggest concern is actually how to get from here to be able to use findAll(), to auto generate my files as described in the initial post. Any idea why it works with findByUid() and not with findAll?
Mikel
2017-11-07 16:00:07 UTC
Permalink
Post by christian ewigfrost
But really thanks... So far at least i can access the repository but my biggest concern is actually how to get from here to be able to use findAll(), to auto generate my files as described in the initial post. Any idea why it works with findByUid() and not with findAll?
The repository expects a storage page by default. As you don’t have a module nor a plugin, your typoscript settings are ignored in that case.
So you have to set the repository to disrespect the storage page globally or you can set it in your task.

Example for ignore the storage page in the task only:

public function execute() {
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
/** @var CustomerRepository $apprep */
$apprep = $objectManager->get(\Conversion\ConversionWebsite\Domain\Repository\CustomerRepository::class);
/** @var Typo3QuerySettings $querySettings */
$querySettings = $objectManager->get(Typo3QuerySettings::class);
$querySettings->setRespectStoragePage(FALSE);
$apprep->setDefaultQuerySettings($querySettings);

\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($apprep->findAll());

return TRUE;

}

Mikel
christian ewigfrost
2017-11-08 07:21:02 UTC
Permalink
Thank you very much, it seems to have worked flawlessly. But i had to change the line where i create the Typo3QuerySettings object to "'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings'". I had not time to test it yet in its full extent, because i just got to work, but you saved me a lot of trouble and wasted time.
christian ewigfrost
2017-11-07 14:34:16 UTC
Permalink
Sry, i'm an idiot... I forgot a semicolon in the line before.^^

It works now.
Loading...