Typo3 Scheduler - Command Controller: I can't execute a command that uses class repositories of my extension - command

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 the following code. It's an Action i have implemented in the controller of a class of my extension:
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');
}
}
This is the way i implemented the code in the CommandController, but in a similar way it is also implementd in my Action in the Class Controller. Now, what this 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?

I guess the reason here, is the difference between frontend and backend context.This answer here, from a different context, sums it up very nice and is worth a read
Basically, in the frontend context, you have the typoscript configuration, telling the repository where to store and find records. That is not present in the backend context. That is explained in the answer above with this code
module.tx_yourext.persistence < plugin.tx_yourext.persistence

As it didn't work with the CommandController for my specific case and i had no access to the persistence layer with with it, not even with dependency injection, i decided to not use CommandContoller tasks at all, but rather the normal Scheduler task for it. The biggest problem i encountered was to actually use the findAll() function for the repositories (it worked with findByUid(). This was because the repository expects a storage page by default. As i don’t have a module nor a plugin, my typoscript settings were ignored in that case.
So i had to set the repository to disrespect the storage page in my task. Here the code:
<?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');
/** #var CustomerRepository $apprep */
$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class);
/** #var Typo3QuerySettings $querySettings */
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$apprep->setDefaultQuerySettings($querySettings);
$hosts = $apprep->findAll();
/** #var CustomerRepository $apprep2 */
$apprep2 = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\ServicesRepository::class);
/** #var Typo3QuerySettings $querySettings */
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$apprep2->setDefaultQuerySettings($querySettings);
$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');
}
return TRUE;
}
}

Related

How do I send variables to an error layout in ZF3?

What is right way to send variables to the layout templete for it be approachable in error pages?
I have AppFrontController above all my frontend controllers. It have code (code is near) in onDispatch() method:
$assocArrayOfVars = $this->MyPlugin()->getDbVariablesArray();
foreach($assocArrayOfVars as $name => $value){
$this->layout()->$name = $value;
}
list($catalog, $count_goods) = $this->MyPlugin()->getStandardCatalogDataForLayout();
$this->layout()->catalog = $catalog;
$this->layout()->count_goods = $count_goods;
As the result, I have my local variables in every frontend page. But I have’nt it in an error page. How I can to deside this problem? I very need your advices! Thank you!
Thank you for your advices! Problem is solved. Code of final version Module.php file below. I use listener instead of a “parent controller” by froschdesign advice.
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach('dispatch', array($this, 'loadConfiguration'), 2);
$eventManager->attach('dispatch.error', array($this, 'loadConfiguration'), 2);
}
public function loadConfiguration(MvcEvent $e)
{
$application = $e->getApplication();
$sm = $application->getServiceManager();
$sharedManager = $application->getEventManager()->getSharedManager();
$router = $sm->get('router');
$request = $sm->get('request');
$zendCart = $sm->get('ControllerPluginManager')->get('ZendCart');
$myPlugin = $sm->get('ControllerPluginManager')->get('MyPlugin');
$viewModel = $e->getViewModel();
$viewModel->setVariable('total', $zendCart->total());
$viewModel->setVariable('total_items', $zendCart->total_items());
$viewModel->setVariable('rusmonth', $rusmonth);
/* Layout variables */
$assocArrayOfVars = $myPlugin->getDbVariablesArray();
foreach ($assocArrayOfVars as $name => $value) {
$viewModel->setVariable($name, $value);
}
list($catalog, $count_goods) = $myPlugin->getStandardCatalogDataForLayout();
$viewModel->setVariable('catalog', $catalog);
$viewModel->setVariable('count_goods', $count_goods);
}
More listener examples here.

How to use Sugarcrm\Sugarcrm\Util\Uuid::uuid1() in a custom entry point?

I am learning suitecrm. I need to create a new bean using a specific id from a custom entry point, generating the id is not working, when i try this code
// Create bean
$testAccountBean = BeanFactory::newBean('Accounts');
// Set the new flag
$testAccountBean->new_with_id = true;
$id = Sugarcrm\Sugarcrm\Util\Uuid::uuid1();
$testAccountBean->id = $id;
$testAccountBean->name = generateRandomString();
$testAccountBeanId = $testAccountBean->save();
echo $testAccountBeanId;
I get nothing
When I inspect the result of calling Sugarcrm\Sugarcrm\Util\Uuid::uuid1() nothing get in return.
Thanks for any idea
The function is called create_guid, require the include/utils.php and you will be able to call it.
<?php
if (!defined('sugarEntry')) {
define('sugarEntry', true);
}
require_once 'data/BeanFactory.php';
require_once 'include/utils.php';
$testAccountBean = BeanFactory::newBean('Accounts');
$id = create_guid();
Having said so - If you do $testAccountBean->new_with_id = true; it means you will provide your own ID, we use that to insert IDs from other systems/migrations. But if you need the GUID just remove that line and suitecrm will generate it for you.
You will need to call it in following manner:
$testAccountBean->new_with_id = true;
$testAccountBean->id = create_guid();
Note that if you assigned your own ID using create_guid function then "new_with_id" need to be set as well. You can find function at this path: include\utils.php
Following is the function body:
function create_guid()
{
$microTime = microtime();
list($a_dec, $a_sec) = explode(' ', $microTime);
$dec_hex = dechex($a_dec * 1000000);
$sec_hex = dechex($a_sec);
ensure_length($dec_hex, 5);
ensure_length($sec_hex, 6);
$guid = '';
$guid .= $dec_hex;
$guid .= create_guid_section(3);
$guid .= '-';
$guid .= create_guid_section(4);
$guid .= '-';
$guid .= create_guid_section(4);
$guid .= '-';
$guid .= create_guid_section(4);
$guid .= '-';
$guid .= $sec_hex;
$guid .= create_guid_section(6);
return $guid;
}

ZfcUser - flash messages after user registration

I'm trying to add some flash messages after user registered
$sharedManager->attach('ZfcUser\Service\User', 'register.post', function($e) use($serviceManager) {
$user = $e->getParam('user');
$mail = new Mail\ActivateAccount($serviceManager, $user);
$mail->send($user->getEmail());
$flash = $serviceManager->get('ControllerPluginManager')->get('flashMessenger');
$flash->addSuccessMessage('Check your mailbox, please.');
});
However, after I was redirected to login page I didn't see any message. Anybody knows the reason?
There is view helper that displays messages
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\View\Helper\FlashMessenger;
class ShowMessages extends AbstractHelper
{
public function __invoke()
{
$messenger = new FlashMessenger();
$error_messages = $messenger->getErrorMessages();
$messages = $messenger->getSuccessMessages();
$result = '';
if (count($error_messages)) {
foreach ($error_messages as $message) {
$result .= '<p class="alert alert-danger">' . $message . '</p>';
}
}
if (count($messages)) {
foreach ($messages as $message) {
$result .= '<p class="alert alert-success">' . $message . '</p>';
}
}
return $result;
}
}
On other pages flash messages works fine.
Thanks!
I found my mistake. I created new messenger instead of getting it throuhg service locator.
$messenger = new FlashMessenger();
should be
$messenger = $this->sm->getServiceLocator()->get('ControllerPluginManager')->get('flashMessenger');

Magento - Get list of all Manufacturers with product count

I am using the following code to list all the manufacturers and it works like a charm:
$attribute = Mage::getModel('eav/entity_attribute')
->loadByCode('catalog_product', 'manufacturer');
$valuesCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute->getData('attribute_id'))
->setStoreFilter(0, false);
$preparedManufacturers = array();
foreach($valuesCollection as $value) {
$preparedManufacturers[$value->getOptionId()] = $value->getValue();
}
if (count($preparedManufacturers)) {
echo "<h2>Manufacturers</h2><ul>";
foreach($preparedManufacturers as $optionId => $value) {
echo "<li>" . $value . " - (" . $optionId . ")</li>";
}
echo "</ul>";
}
What I am looking for is a way to display the number of products associated with each of the manufacturers. Can someone please tell me the way of doing this?
Many thanks
Not all mine, but works for me in 1.6+?
<?php
include_once 'app/Mage.php';
Mage::app();
$attribute = Mage::getModel('eav/entity_attribute')
->loadByCode('catalog_product', 'manufacturer');
$valuesCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute->getData('attribute_id'))
->setStoreFilter(0, false);
$preparedManufacturers = array();
foreach ($valuesCollection as $value) {
$preparedManufacturers[$value->getOptionId()] = $value->getValue();
}
if (count($preparedManufacturers)) {
echo "<h2>Manufacturers</h2><ul>";
foreach ($preparedManufacturers as $optionId => $value) {
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addFieldToFilter(array(array('attribute' => 'manufacturer', 'eq' => $optionId)));
$mumberOfProducrt = count($collection);
echo "<li>" . $value . " - (" . $mumberOfProducrt . ")</li>";
}
echo "</ul>";
}
?>
This would work but won't be the most efficient:
foreach($valuesCollection as $value) {
$preparedManufacturers[$value->getOptionId()] = $value->getValue();
$collection = Mage::getModel('catalog/product')->getCollection();
$collection
->addAttributeToSelect('*') // '*' not efficient though
->addAttributeToFilter('manufacturer', array('eq' => $value->getOptionId()))
//->addAttributeToFilter('manufacturer', $value->getOptionId())
;
$count = $collection->->getSize();
}
It's an extra query for each manufacturer so it's not great, if you have some caching etc it won't be too bad though.
Working code should do it
$collection = Mage::getModel('catalog/product')->getCollection()->groupByAttribute('manufacturer')
->addFieldToFilter('status',Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->addExpressionAttributeToSelect("count",'COUNT({{entity_id}})', 'entity_id');
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($collection);

Fatal error: Call to a member function prepare() on a non-object in mysqlicon.php on line 62 Help explain OOP mysqli classes and prepared statements [duplicate]

This question already has answers here:
Call to a member function on a non-object [duplicate]
(8 answers)
Closed 10 years ago.
I'm hesitant to post this, as I'd really prefer to figure this out myself, but I don't think I will. I'm just trying to set a class for mysqli stuff, to make it as dynamic as possible, and yes I'm newer to OOP, but have been using PHP and Mysql as a hobby, and more heavily lately, for quite some time. I figured it was time to switch, but there just isn't that much on oop classes with mysqli and prepared statements with a possibility of multiple results (yes I've check documentation, guess I'm just not getting it or something). After quite a few hours, this is what I have. I'm not necessarily looking for a "quick fix". I really want to understand this and learn, so please explain thoroughly.
I'm using a dbconfig.php file to store my database info at root/config/dbconfig.php
in root/classes/mysqlicon.php
<?php
/*
* class MYSQLIDB
* #param Host
* #param User
* #param Password
* #param Name
*/
class MYSQLIDB
{
private $host; //MySQL Host
private $user; //MySQL User
private $pass; //MySQL Password
private $name; //MySQL Name
private $mysqli; //MySQLi Object
private $last_query; //Last Query Run
/*
* Class Constructor
* Creates a new MySQLi Object
*/
public function __construct()
{
include('./config/dbconfig.php');
$this->host = $db_host;
$this->user = $db_user;
$this->pass = $db_pass;
$this->name = $db_name;
$this->mysqli = new mysqli($this->host, $this->user, $this->pass, $this->name);
if ($mysqli->connect_errno) {
return "Failed to connect to MySQLi: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
}
private function __destruct()
{
$mysqli->close();
}
public function select($fields, $from, $where, $whereVal, $type, $orderByVal, $ASDESC, $limitVal)
{
if (is_int($whereVal))
{
$bindVal = 'i';
} else {
$bindVal = 's';
}
switch($type)
{
case "regular":
$queryPre = "SELECT " . $fields;
$querySuff = " WHERE " . $where . " = ?";
break;
case "orderByLimit":
$queryPre = "SELECT " . $fields;
$querySuff = " ORDER BY " . $orderByVal . " " . $ASDESC . " LIMIT " . $limitVal;
break;
}
//$query = "SELECT * FROM news ORDER BY id DESC LIMIT 4";
if ($stmt = $mysqli->prepare('$queryPre . " FROM " . $from . " " . $querySuff'))
{
if ($type == 'regular') {
$stmt->bind_param($bindVal, $whereVal);
}
$stmt->execute();
$stmt->bind_result($values);
$stmt->store_result();
$sr = new Statement_Result($stmt);
$stmt->fetch();
// call by this style printf("ID: %d\n", $sr->Get('id') );
//$stmt->fetch();
//$stmt->close();
//return $value;
printf("ID: %d\n", $sr->Get_Array() );
} else return null;
}
//use to call $db = new MYSQLI('localhost', 'root', '', 'blog');
/*
* Function Select
* #param fields
* #param from
* #param where
* #returns Query Result Set
function select($fields, $from, $where, $orderBy, $ASDESC, $limit, varNamesSent)
{
if ($orderBy == null &&)
$query = "SELECT " . $fields . " FROM `" . $from . "` WHERE " . $where;
$result = $this->mysqli->query($query) or exit("Error code ({$sql->errno}): {$sql->error}");
$this->last_query = $query;
return $result;
}
/*
* Function Insert
* #param into
* #param values
* #returns boolean
*/
public function insert($into, $values)
{
$query = "INSERT INTO " . $into . " VALUES(" . $values . ")";
$this->last_query = $query;
if($this->mysqli->query($query))
{
return true;
} else {
return false;
}
}
/*
* Function Delete
* #param from
* #param where
* #returns boolean
*/
public function delete($from, $where)
{
$query = "DELETE FROM " . $from . " WHERE " . $where;
$this->last_query = $query;
if($this->mysqli->query($query))
{
return true;
} else {
return false;
}
}
}
//Hand arrays for multiple returned items from database
class Statement_Result
{
private $_bindVarsArray = array();
private $_results = array();
public function __construct(&$stmt)
{
$meta = $stmt->result_metadata();
while ($columnName = $meta->fetch_field())
$this->_bindVarsArray[] = &$this->_results[$columnName->name];
call_user_func_array(array($stmt, 'bind_result'), $this->_bindVarsArray);
$meta->close();
}
public function Get_Array()
{
return $this->_results;
}
public function Get($column_name)
{
return $this->_results[$column_name];
}
}
?>
And just as a test, I'm trying to pull all the news in my db by:
<?php
require_once('classes/mysqlicon.php');
$testing = new MYSQLIDB;
$testing->select('*','news',null,null,'orderByLimit','id','DESC',4);
?>
But what I really want is stuff that can do the equivalent of this:
<?php
/*
require('config/dbconfig.php');
$query = "SELECT * FROM news ORDER BY id DESC LIMIT 4";
if ($stmt = $mysqli->prepare($query)) {
// execute statement
$stmt->execute();
// bind result variables
$stmt->bind_result($idn, $titlen, $categoryn, $descn, $postdaten, $authorn);
// fetch values
while ($stmt->fetch()) {*/
//echo 'id: '. $id .' title: '. $title;
echo "<table border='0'>";
$shortDescLengthn = strlen($descn);
if ($shortDescLengthn > 106) {
$sDCutn = 106 - $shortDescLengthn;
$shortDescn = substr($descn, 0, $sDCutn);
} else {
$shortDescn = $descn;
}
echo "<h1>$titlen</h1>";
echo "<tr><td>$shortDescn...</td></tr>";
echo '<tr><td><a href="javascript:void(0);" onclick="'
. 'readMore(' . $idn . ',' . htmlspecialchars(json_encode($titlen)) . ','
. htmlspecialchars(json_encode($categoryn)) . ','
. htmlspecialchars(json_encode($descn)) . ',' . htmlspecialchars(json_encode($postdaten)) . ','
. htmlspecialchars(json_encode($authorn)) . ')">Read More</a></td></tr>';
echo "<tr><td>Written by: $authorn</td></tr>";
echo '<tr><td><img src="images/hardcore-games-newsbar-border.png" width="468px" /></td></tr>';
}
echo "</table><br />";
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
?>
Again, please, please explain in detail. I'm a blockhead sometimes.
I'm assuming the error is coming from this line:
if ($stmt = $mysqli->prepare('$queryPre . " FROM " . $from . " " . $querySuff'))
$mysqli is not defined in the context of this function. You should be accessing $this->mysqli instead. The same applies to other references you have made such as here:
if ($mysqli->connect_errno)