Calling console command within command and get the output in Symfony2 - php

I have a few console command in Symfony2 and I need to execute one command from another command with some parameters.
After successfull execution of the second command I need to get the result (as an array for example), not the display output.
How can I do that?

Here you can have a basic command inside a command. The output from the second command can be a json, then you just have to decode the output json to retrieve your array.
$command = $this->getApplication()->find('doctrine:fixtures:load');
$arguments = array(
//'--force' => true
''
);
$input = new ArrayInput($arguments);
$returnCode = $command->run($input, $output);
if($returnCode != 0) {
$text .= 'fixtures successfully loaded ...';
$output = json_decode(rtrim($output));
}

you have to pass the command in the arguments array, and to avoid the confirmation dialog in doctrine:fixtures:load you have to pass --append and not --force
$arguments = array(
'command' => 'doctrine:fixtures:load',
//'--append' => true
''
);
or it will fail with error message “Not enough arguments.”

There is an new Output class (as of v2.4.0) called BufferedOutput.
This is a very simple class that will return and clear the buffered output when the method fetch is called:
$output = new BufferedOutput();
$input = new ArrayInput($arguments);
$code = $command->run($input, $output);
if($code == 0) {
$outputText = $output->fetch();
echo $outputText;
}

I did the following
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
$tmpFile = tmpfile();
$output = new StreamOutput($tmpFile);
$input = new ArrayInput(array(
'parameter' => 'value',
));
$command = . . .
$command->run($input, $output);
fseek($tmpFile, 0);
$output = fread($tmpFile, 1024);
fclose($tmpFile);
echo $output;
¡it works!

I understand it's old post and above answers solves the problem with a bit of digging. In Symfony2.7, I had a bit issue making it work, so with above suggestions, I dug a little and have compiled the full answer here. Hope it will be useful for someone.
Using Console command under console command

As an update for Onema's answer, in Symfony 3.4.x (used by Drupal 8),
you also need to set setAutoExit(false),
and the command returns an int(0) if successful.
Here's the updated example that I'm using to script composer commands in php for a Drupal 8.8 project. This gets a list of all composer packages as json, then decodes that into a php object.
<?php
require __DIR__.'/vendor/autoload.php';
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Composer\Console\Application;
$input = new ArrayInput([
'command' => 'show',
'--format'=>'json',
]);
$output = new BufferedOutput();
$application = new Application();
// required to use BufferedOutput()
$application->setAutoExit(false);
// composer package list, formatted as json, will be barfed into $output
$status = $application->run($input, $output);
if($status === 0) {
// grab the output from the $output buffer
$json = $output->fetch();
// decode the json string into an object
$list = json_decode($json);
// Profit!
print_r($list);
}
?>
The output will be something like this:
stdClass Object
(
[installed] => Array
(
... omitted ...
[91] => stdClass Object
(
[name] => drupal/core
[version] => 8.9.12
[description] => Drupal is an open source content management platform powering millions of websites and applications.
)
... omitted ...
)
)
With the help of Onema's hint Google found the rest of the solution for me here.

Related

Get data to/from secondary PHP file - works with some data, not with other

I have a SPA (react) that is uses PHP calls to connect to a MongoDB.
Works great.
However, due to 'rules' I need to serve the javascript files from a different server -- a server that supports neither MongoDB nor MongoDB php client. Let's call this server, SERVER_A.
Let's call the server hosting the MongoDB PHP client and the MongoDB, SERVER_B. ('B' for 'backend'... :) )
The solution, I believe, was to build a php 'middleman' on SERVER_A that simply passes data on to SERVER_B. Research shows me that file_get_contents is the tool for this.
So I take my original known-working PHP file, I put it on SERVER_B and rename it to "mongoPatch_backend.php".
<?php
$user = "xxxx";
$pwd = 'xxx';
$filter = [];
if (isset($_REQUEST['needleKey'])) {
$needleKey = $_REQUEST['needleKey'];
$needle = $_REQUEST['needle'];
$filter = [$needleKey => $needle];
}
$newData = $_REQUEST['newData'];
$filter = ['x' => ['$gt' => 1]];
$options = [
'projection' => ['_id' => 0],
'sort' => ['x' => -1],
];
$bson = MongoDB\BSON\fromJSON($newData);
$value = MongoDB\BSON\toPHP($bson);
$manager = new MongoDB\Driver\Manager("mongodb://${user}:${pwd}#SERVER_B:27017");
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->update(
[$needleKey => $needle],
['$set' => $value],
['multi' => false, 'upsert' => true]
);
$results = $manager->executeBulkWrite('sedwe.users', $bulk);
var_dump($results);
?>
On SERVER_A I then make a new file, dbPatch.php, like so:
<?php
$API = "https://SERVER_B/php/mongoPatch_backend.php?";
if (isset($_REQUEST['needleKey'])) {
$needleKey = $_REQUEST['needleKey'];
$needle = $_REQUEST['needle'];
$filter = [$needleKey => $needle];
}
$newData = $_REQUEST['newData'];
$postData = "needleKey=".urlencode($needleKey);
$postData .= "&needle=".urlencode($needle);
$postData .= "&newData=".urlencode($newData);
// echo $API.$postData;
$data = file_get_contents($API.$postData);
echo $data;
?>
But when I call it, I get nothing echo'd back out of $data.
Any idea why? Remember, the exact same call directly to mongoPatch_backend.php works just fine (but it's a CORS call, so it's not a valid option).
So here is what I've tried:
First, to ensure my AJAX call was still working, I spit out the response to the console. I get nothing.
So I changed the last line of the middleman (dbPatch.php) to echo "Hello World" instead of echo $data and received "Hello World" on the console as expected.
Next, I then changed the last line of my middleman (dbPatch.php) back to echo $data and tried reducing the 'backend' to a simple <?php echo "Hello Back World"; ?> and got nothing on the console.
Next, I go to https://SERVER_B/php/mongoPatch_backend.php in a browser ... and I'm greeted with "Hello Back World" as expected in the browser.
... which leads me to believe something is up with the transferring of info from server to server. Logical call, eh?
Unfortunately, when I try the same thing with just a 'fetch' command, it works perfectly fine:
Here is my 'middleman' (dbFetch.php) script on SERVER_A:
<?php
$API = "https://SERVER_B/php/mongoFetch_backend.php?";
$collection = $_REQUEST['collection'];
$postData = "collection=".urlencode($collection);
$needleID = $_REQUEST['needleID'];
$postData .= "&needleID=".urlencode($needleID);
$data = file_get_contents($API.$postData);
echo $data;
?>
And this is the file on the backend, SERVER_B:
<?php
$user = "xxxx";
$pwd = 'xxxx';
$filter = [];
if (isset($_REQUEST['needleID'])) {
$needleID = $_REQUEST['needleID'];
$filter = ['id'=> $needleID];
}
if (isset($_REQUEST['collection'])) {
$collection = $_REQUEST['collection'];
}
//Manager Class
$connection = new MongoDB\Driver\Manager("mongodb://${user}:${pwd}#SERVER_B:27017");
// Query Class
$query = new MongoDB\Driver\Query($filter);
$rows = $connection->executeQuery("db_name.$collection", $query);
// Convert rows to Array and send result back to client
$rowsArr = $rows->toArray();
echo json_encode($rowsArr);
?>
Huzzah, this works! ... and it's also proof there doesn't appear to be a problem with the server-to-server communication.
So back to ground zero.
I then go with a very simple newData value -- shorter, but same general layout - stringified json. It works! The data ends up in the database.
So I'm forced to think something is wrong with the data in newData (which is only a few hundred lines of stringified JSON made like this: encodeURIComponent(JSON.stringify(newData)). But, this bears repeating: this works if I skip the middleman.
... and that puts me at a loss. PHP isn't something I understand well... can you help?
EDIT to answer comment:
When I call mongoPatch_backend.php directly on SERVER_B it works (as stated above). I had it echo the $newData and it spits out a stringified JSON version of the variable (not URLencoded).
When I call dbPatch.php, it does not give me anything that was passed back from mongoPatch_backend.
As I said in the OP, if I modify mongoPatch_backend.php to do nothing other than echo "hellow world" I am still unable to log it to console when calling it via the above dbPatch.php file.
EDIT: I also tried putting the two PHP files on the same server and am getting the same results. (ie: both the dbPatch.php and mongoPatch.php files are in the same directory on the same server)
EDIT2: I have done a var_dump from the middleman and I get standard-looking human-readable stringified text back.
I do the same var_dump($_REQUEST['newData']); in the backend file and I get nothing back.

Get console.log from Selenium using php webdriver

I'm trying to run integration tests against some of our AMP pages to see if they validate. AMP runs validation if you append #development=1 to a URL and puts the results in console.log. I need to be able to read console.log to check this.
This is what I have so far:
$caps = DesiredCapabilities::firefox();
$caps->setCapability('loggingPrefs', array('browser'=>'ALL'));
//connect to selenium
$webdriver = RemoteWebDriver::create('http://127.0.0.1:4444/wd/hub', $caps);
$webdriver->get('https://www.example.com/amp/page.html#development=1');
sleep(10);
$logs = $webdriver->manage()->getLog('browser');
var_dump($logs);
Using Facebook's webdriver for PHP. I can get the logs back, but it doesn't seem to include anything from console.log. How can I capture this data?
As far as I can tell, the Facebook PHP WebDriver implementation does not seem to implement any of the LoggingPreferences "facilities". However, because PHP is what-I-believe-is-called weakly typed, you can "cheat" by making a call to:
$chromeCapabilities->setCapability( 'loggingPrefs', ['browser' => 'ALL'] );
And then later, call (say)
var_dump( $chromeDriver->manage()->getLog( 'browser' ) );
to access the console log.
The following is a working sample I used to get this working after about 30 hours of investigation - I hope it helps someone! It can use Selenium or not, if not, then it calls the ChromeDriver directly. The test site includes some JavaScript to explicitly write to the console.log:
<?php
require_once (__DIR__.'/../vendor/autoload.php');
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Chrome;
$javaPath = '"C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath\\java.exe"';
$seleniumPath = '"'. __DIR__ . '\\..\\selenium-server-standalone-3.141.5.jar"';
$chromeDriverPath = 'C:\path\to\chromedriver.exe';
$site = 'http://mytestsite';
$seleniumPort = 4445;
$useSelenium = true;
$chromeDriverPathEnvVar = 'webdriver.chrome.driver';
putenv( $chromeDriverPathEnvVar .'='. $chromeDriverPath );
$chromeOptions = new Chrome\ChromeOptions();
$chromeOptions->addArguments( array( '--headless' ) );
$chromeCapabilities = DesiredCapabilities::chrome();
$chromeCapabilities->setCapability( Chrome\ChromeOptions::CAPABILITY, $chromeOptions );
$chromeCapabilities->setCapability( 'loggingPrefs', ['browser' => 'ALL'] );
$selenium = null;
if ($useSelenium) {
$descriptorspec = array(
0 => array('pipe', 'r'), // stdin is a pipe that the child will read from
1 => array('file', __DIR__ . '/selenium_log-' . date('Ymd-His').'_'. $seleniumPort . '-stdout.txt', 'a'), // stdout is a pipe that the child will write to
2 => array('file', __DIR__ . '/selenium_log-' . date('Ymd-His').'_'. $seleniumPort . '-stderr.txt', 'a') // stderr is a file to write to
);
$selenium_cmd = $javaPath .' -D'. $chromeDriverPathEnvVar .'="'. $chromeDriverPath .'" -jar '. $seleniumPath .' -port '. $seleniumPort; // If interested, add .' -debug';
$selenium = proc_open( $selenium_cmd, $descriptorspec, $pipes, null, null, array( 'bypass_shell' => true ) );
$host = 'http://localhost:'. $seleniumPort .'/wd/hub'; // this is the default
$chromeDriver = RemoteWebDriver::create($host, $chromeCapabilities );
} else {
$chromeDriver = Facebook\WebDriver\Chrome\ChromeDriver::start( $chromeCapabilities );
}
$chromeDriver->get( $site );
var_dump( $chromeDriver->manage()->getLog( 'browser' ) );
$chromeDriver->quit(); sleep(1);
$chromeDriver->action(); sleep(1);
$chromeDriver->close();
if ($useSelenium) {
fclose( $pipes[0] );
proc_terminate( $selenium );
#pclose( $selenium );
}
I was banging my head against this for a while- getting an empty array returned from $driver->manage()->getLog('browser');. Then I found this github issue. I changed
$desiredCapabilities->setCapability('loggingPrefs', ['browser'=>'ALL']); to
$desiredCapabilities->setCapability('goog:loggingPrefs', ['browser'=>'ALL']);. The difference was adding in goog: before loggingPrefs.
After that, whammo, $driver->manage()->getLog('browser'); returns a non-empty array =).

How to call cache:clear command with argumemt within another command - Symfony3

I know that I can run a command within another command.
like this example..
$command = $this->getApplication()->find('cache:clear');
$arguments = array();
$input = new ArrayInput($arguments);
$returnCode = $command->run($input, $output);
$text = '';
if ($returnCode != 0) {
$text .= 'successfully...';
}
$output->writeln($text);
But when I trying to run the cache:clear command with their options-
$arguments = array(
'--env=prod' => true
);
I get the following error
[Symfony\Component\Console\Exception\InvalidOptionException]
The "--env=prod" option does not exist.
How can I run this command?
You should use it like:
$arguments = array(
'--env' => 'prod',
);
-- is only needed when passing an option, not an argument.
To make your command able to consider your argument, just use:
$arguments = ['env' => 'prod'];
If it doesn't work, simply use $input->setArgument('env', 'prod');

Error "Class 'Zend_Config_Writer_Xml' not found" when integrate Zend libary into CodeIgniter?

I copy some Zend libraries and paste them into libraries folder in CodeIgniter. I try to use this code, it's ok:
$this->zend->load('zend/json');
$data = array(
'name' => 'Killer Whale',
'email' => 'namnguyen2091#gmail.com',
'website' => 'baogiadientu.com'
);
// load and encode data
$json = new Zend_Json();
$encode = $json->encode($data);
echo $encode;
//decode with static function
echo '<pre>';
print_r(Zend_Json::decode($encode));
echo '</pre>';
But when I code like below, it doesn't work and I get an error:
Fatal error: Class 'Zend_Config_Writer_Xml' not found in D:\Programs\xampp\htdocs\baogiadientu\application\controllers\product.php on line 83
$this->zend->load('zend/config');
// create the config object
$config = new Zend_Config(array(), true);
$config->production = array();
$config->production->webhost = 'baogiadientu.com';
$config->production->database = array();
$config->production->database->params = array();
$config->production->database->params->host = 'localhost';
$config->production->database->params->username = 'root';
$config->production->database->params->password = '123456';
$config->production->database->params->dbname = 'baogiadientu';
$writer = new Zend_Config_Writer_Xml(); // **here**
echo $writer->toString($config);
I follow this article http://framework.zend.com/manual/2.0/en/modules/zend.config.writer.html. Please help me!
You are trying to do two things there (1) load and instantiate a Zend Config object and (2) do the same with Zend_Config_Writer_Xml - all without including the required files.
You may just need to require("Zend/Config.php") and require("Zend/Config/Writer/Xml.php") after ensuring they are inside your include_path
You are using a ZF1 library with the ZF2 documentation
Please check the correct documentation at their website:
http://framework.zend.com/manual/1.12/en/zend.config.writer.introduction.html

Amazon MWS Product Feed Not Submitting

I am working on the Amazon API. I want to submit the product feed on amazon account.
I have validated the XML file (product feed) by the Amazon Scratch Pad and i get the Response that Feed is submitted but when i run the script, to submit the same feed by script, i don't get any response.
Here is my code :
$req = new MarketplaceWebService_Model_SubmitFeedRequest();
$req->setMerchant(MERCHANTID);
$req->setMarketplaceIdList(MARKETPLACEID);
$req->setFeedType('_POST_PRODUCT_DATA_');
$req->setContentMd5(base64_encode(md5(stream_get_contents($fh), true)));
rewind($fh);
$req->setPurgeAndReplace(true);
$req->setFeedContent($fh);
$res = $mws->submitFeed($request);
echo $res;
I am unable to get the response, when i echo the $res.
I have changed the $res = $mws->submitFeed($request); to $res = $mws->submitFeed($req);. Still no success in submitting the feed. I am not getting any response header that Amazon return while submitting the feed.
The code is like this :
$req = new MarketplaceWebService_Model_SubmitFeedRequest();
$fh = fopen('feed.xml', 'r');
$req->setMerchant(MERCHANTID);
$req->setMarketplaceIdList(MARKETPLACEID);
$req->setFeedType('_POST_PRODUCT_DATA_');
$req->setContentMd5(base64_encode(md5(stream_get_contents($fh), true)));
rewind($fh);
$req->setPurgeAndReplace(true);
$req->setFeedContent($fh);
$res = $mws->submitFeed($req);
echo $res;
Apart from other things that might go wrong: You are submitting $request, while the thing you probably want to submit is $req.
Edit: Since you corrected this mistake but still have no result...:
submitFeed() returns a MarketplaceWebService_Model_SubmitFeedResponse object.
Echo does not work with objects, unless the object has a __toString() method, which this class doesn't. Try using print_r($res) or var_dump($res) instead.
Try this
$marketplaceIdArray = array("Id" => array($MARKETPLACE_ID));
$feedHandle = #fopen('php://temp', 'rw+');
fwrite($feedHandle, $feed);
rewind($feedHandle);
$parameters = array(
'Merchant' => $MERCHANT_ID,
'MarketplaceIdList' => $marketplaceIdArray,
'FeedType' => '_POST_PRODUCT_DATA_',
'FeedContent' => $feedHandle,
'PurgeAndReplace' => false,
'ContentMd5' => base64_encode(md5(stream_get_contents($feedHandle), true))
);
rewind($feedHandle);
$request = new MarketplaceWebService_Model_SubmitFeedRequest($parameters);
$return_feed = invokeSubmitFeed($service, $request);
fclose($feedHandle);

Categories