PHP Reflection class newInstance exit on execution - php

I'm writing controller testing unit with Fuelphp framework. And inside the code I'm trying to request application controller like this one :
$response = Request::force('controller_name/controller_method')->set_method('GET')->execute();
But this code unexpectedly exits the entire testing unit like PHP exit function. After trying to figure out what happened inside the core source code, I found out that in line 440 of https://github.com/fuel/core/blob/1.9/develop/classes/request.php forces the program to exit without any exception.
$this->controller_instance = $class->newInstance($this);
And before this code
$class = new \ReflectionClass($this->controller)
I'm using PHP 5.6.33 and Fuelphp 1.7.2 in my machine and I hope someone can help me with this error.

I think it's just a typo in your question but to be sure : you said
Request::force
instead of
Request::forge
Anyway, I have a lot of tests wrote in the same way but we add few lines before calling forge it :
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['HTTP_ACCEPT'] = 'application/json'; // this one may not be required for you
$_POST = array();
$_GET = array();
$request = \Request::forge('controller/action')->set_method('GET');
$request->execute();

Related

PHP mock test not working at the method call part inside PHPUnit

I'm running PHP 8 on PHPStorm, and I'm trying to create a test for a function that returns an IP string. I'm using PHPUnit & PHPMock
I have the following code inside my test:
$UserIpAddress = $this->getFunctionMock(__NAMESPACE__, 'ip_request');
$UserIpAddress->expects($this->once())
->method('getRealIpAddr')
->willReturn('127.0.0.1');
My error is
Method name is already configured
Yet when I remove it, I get an error that it's expected to be called.
I have copied and pasted the function name, and it definitely is inside the correct class.
My namespaces are correct, and the actual page that uses the function works fine.
Any ideas?
Thanks
Fixed! After a ton of checking various options, the code that should go in the test file is
$local = new ip_request();
$this->assertEquals('127.0.0.1', $local->getRealIpAddr());
and inside the actual class file
$ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
I don't think the ?? '127.0.0.1' should be left in for production though.

PHP prints out a buffer string into web-page on certain circuntances?

I don't know how to explain it but, I'm gonna give it a try.
This problem concerns 2 servers, a local and a hosting server. Both servers are running the same PHP version which is 7.0 [with almost same configurations]. And 2 controller actions. And the problem comes from $app->run($input, $out); from the codes below.
I have in my controller that action:
/**
* #Route("/testJson")
*/
public function testJsonAction() {
$app = new \Symfony\Bundle\FrameworkBundle\Console\Application($this->get("kernel"));
$app->setAutoExit(false);
$opt = array("command" =>
"doctrine:generate:entity",
"--entity" => "GuervylEditorBundle:TestOnline",
"--fields" => "kl:string");
$input = new \Symfony\Component\Console\Input\ArrayInput($opt);
$out = new \Symfony\Component\Console\Output\BufferedOutput();
$app->run($input, $out);
$out->fetch();
return new JsonResponse(\json_encode(["a" => "b", "c" => "d"]));
}
Calling this action from the local and hosting server returns "{\u0022a\u0022:\u0022b\u0022,\u0022c\u0022:\u0022d\u0022}" and with Content-Type
application/json which is great, it's the expected result.
Now, here comes the problem:
That almost same code above, I set it inside another class, I call it from another controller action, which passes through 4 methods from different classes to call the method that has the code above [callCommand]
This is the method that implement the code:
public function callCommand($cmd, $opt, &$mykernel = null) {
if ($mykernel == NULL) {
$mykernel = new myKernel("dev", false, __DIR__ . "/../Resources/template_2.8/app");
}
$app = new \Symfony\Bundle\FrameworkBundle\Console\Application($mykernel);
$app->setAutoExit(false);
$opt = array("command" => $cmd) + $opt;
$input = new \Symfony\Component\Console\Input\ArrayInput($opt);
$out = new \Symfony\Component\Console\Output\BufferedOutput();
$app->run($input, $out);
}
From that other controller action, I also return a json content at the end. I can't show the code because it's too big.
When I call that controller action from my localhost, I get the JSON content and Content-Type: application/json which is fine.
But calling it from the hosting server I get extra texts like:
Entity generation
created ./src/Guervyl/EditorBundle/Entity/TestCase.php
> Generating entity class src/Guervyl/EditorBundle/Entity/TestCase.php: OK!
> Generating repository class src/Guervyl/EditorBundle/Repository/TestCaseRepository.php: OK!
Everything is OK! Now get to work :).
Which is the output texts from the console when calling $app->run($input, $out);. After that I get the HTTP header that I set then the json content. And also the content-type is application/x-httpd-php5.
That error only happens on a specific hosting server. I tested other hosting server the code works like on my local server.
My question is why am I getting the error on that specific hosting? Is there something I can change from the PHP.ini to fix it? Because I really need to host my website on that hosting because it offers me great features that I need but the others don't or they are too expensive.
Well, After I debugged the code I noticed that error happened because I did not set the --no-interaction option. So without that option, Symfony was waiting for input when no fields are specified for an Entity.

How laravel classes are included?

I want to run custom php code in laravel directly without using any routes or http requests..
I hope I can make it clear, I mean, like those online tools that runs php code by writing php code in browser, and then run it, and view result..
I found this handy project (Run-PHP-Code) to run PHP in browser directly, but I can't use models of my laravel project in PHP code..
How can I include laravel 's environment, so that I can for example:
$tag= new Tag;
where Tag is a model in laravel project, that would result into:
Fatal error: Class 'Tag' not found in D:\xampp\htdocs\widgetsRepository\app\controllers\Run-PHP-Code-master\index.php(49) : eval()'d code on line 3
Any idea? this would be very useful!
EDIT
I tried Brian suggestion at his answer, but I got this error now:
Call to a member function connection() on null
at vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
public static function resolveConnection($connection = null)
{
return static::$resolver->connection($connection);
}
so, I think I only need to get database sorted, then I can do experiments easily..
I've never tried to run code from a laravel project directly, I just copy and paste parts of the code into Run PHP Code.
That being said, it should be possible to run the code using the method taken from this StackOverflow question:
The Composer autoload script, to autoload all of your classes:
require __DIR__.'/../bootstrap/autoload.php';
And if you need things from the IoC container, you'll:
$app = require_once __DIR__.'/../bootstrap/start.php';
Then you will be able to do things like:
$post = Post::find(1);

Is there any way to instantiate CodeIgniter and call a function inside a controller from an outside class?

I am creating a cron job that will run every few minutes and it will read from database data to see which function needs to be called and act accordingly to the data but half the crons are written in codeigniter and the other half in native php.
Is there any way to do this? I have been googling but the anwser. I came up with is that it is impossible. I tried changing directory and than including or requiring index.php from the codeigniter, in which the function is that i need to call.
while doing this if my class is written in native php, It returns some errors that don't make sense and if I correct those errors, I would say that half the system function from codeigniter would be gone. It would still be a question if it will work even then.
If my class is written in codeigniter, when I include index.php, it just breaks. No errors no response or it says that the "ENVIRONMENT" variables are already defined. Thus I have been looking for a way to undefine those variables from config file or overwrite them to null or empty string but nothing works.
If you have any ideas it would be much appreciated.
I saw a question question link about some cron jobs in php where the user #michal kralik gave an answer about what i am doing in general with database and one cron class that will call other crons (coould use help for that too).
btw forgot to mention that using curl and exec will not work, because on our servers they sometimes just stop working for no reason.
UPDATE 1:
this is my class currently after so many tries:
class Unicron extends MY_Controller {
public $config;
function __construct() {
parent::__construct();
}
public function init(){
$config['base_url'] = "http://localhost/test";
define('EXT_CALL', true); // Added EXT_CALL constant to mark external calls
$_GET['controller/method'] = ''; // add pair to $_GET with call route as key
$current = getcwd(); // Save current directory path
chdir('C:/inetpub/wwwroot/test/'); // change directory to CI_INSTALLATION
include_once 'index.php'; // Add index.php (CI) to script
define('BASEPATH', 'C:/inetpub/wwwroot/test/system/');
$this->load->library("../../application/controllers/controller.php");
$job = new $this->controller->Class();
$isDone = $job->exportExcel(somekey);
echo $isDone;
$CI =& get_instance(); // Get instance of CI
$CI->exportExcel('baseparts', 'exportExcel');
// FOR STATIC CALLING!!
//$CI->method('controller','method');
//replace controller and method with call route
// eg: $CI->list('welcome','list'); If calling welcome/list route.
//$OUT->_display(); // to display output. (quick one)
// Or if you need output in variable,
//$output = $CI->load->view('VIEW_NAME',array(),TRUE);
//To call any specific view file (bit slow)
// You can pass variables in array. View file will pick those as it works in CI
chdir($current); // Change back to current directory
echo $current;
}
where i try to define BASEPATH it does not define it nor override the previous value.
In the index.php of other codeigniter i put:
if(!defined('ENVIRONMENT'))
define('ENVIRONMENT', 'development');
this way i resolved my issue with ENVIRONMENT already being set error.
this is a few things i found and combined together, hoping it could work but still when i call it via command line it shows nothing (even tried echo anything everywhere and nothing).
This may be a long comment rather than a answer as the code supplied requires a lot of work to make it useful.
Running multiple instances of 'codeigniter' - executed from codeigniter.
Using the 'execute programs via the shell' from PHP. Each instance runs in its own environment.
There are some excellent answers already available:
By default the PHP commands 'shell' wait for the command to complete...
732832/php-exec-vs-system-vs-passthru.
However, we want to 'fire and forget' quite often so this answer is quite useful...
1019867/is-there-a-way-to-use-shell-exec-without-waiting-for-the-command-to-complete
All i did was use this show an example of how to use 'codeigniter' to do this. The example was the 'Hello World' cli example from user manual. The version of ci is 2.1.14. I haven't used 'ci' before.
It is tested and works on 'PHP 5.3.18' on windows xp.
As well as the usual 'Hello World' example, i used an example of a a command that uses 'sleep' for a total of 20 seconds so that we can easily see that the 'ci' instances are separate from each other while executing.
Examples:
<?php
class Tools extends CI_Controller {
// the usual 'hello world' program
public function message($to = 'World')
{
echo "Hello {$to}!".PHP_EOL;
}
// so you can see that the processes are independant and 'standalone'
// run for 20 seconds and show progress every second.
public function waitMessage($to = 'World')
{
$countDown = 20;
while ($countDown >= 0) {
echo "Hello {$to}! - ending in {$countDown} seconds".PHP_EOL;
sleep(1);
$countDown--;
}
}
}
'ci' code to run 'ci' code...
<?php
class Runtools extends CI_Controller {
/*
* Executing background processes from PHP on Windows
* http://www.somacon.com/p395.php
*/
// spawn a process and do not wait for it to complete
public function runci_nowait($controller, $method, $param)
{
$runit = "php index.php {$controller} {$method} {$param}" ;
pclose(popen("start \"{$controller} {$method}\" {$runit}", "r"));
return;
}
// spawn a process and wait for the output.
public function runci_wait($controller, $method, $param)
{
$runit = "php index.php {$controller} {$method} {$param}";
$output = exec("{$runit}");
echo $output;
}
}
How to run them from the cli...
To run the 'ci' 'nowait' routine then do:
php index.php runtools runci_nowait <controller> <method> <param>
where the parameters are the ci controller you want to run. Chnge to 'runci_wait' for the other one.
'Hello World: 'wait for output' - (ci: tools message )
codeigniter>php index.php runtools runci_wait tools message ryan3
Hello ryan3!
The waitMessage - 'do not wait for output' - (ci : tools waitMessage )
codeigniter>php index.php runtools runci_nowait tools waitMessage ryan1
codeigniter>php index.php runtools runci_nowait tools waitMessage ryan2
These will start and run two separate 'ci' processes.

integration testing command line PHP

I've got a PHP script that runs at the command line, executing classes that are already unit tested with PHPUnit.
However, I'd like to verify that the script itself has no logical errors and runs properly.
// require classes
require_once 'injectedClass.php';
require_once 'DBClass.php';
require_once 'taskEngine.php';
$injectedObj = new injectedClass;
$dbObj = new DBClass;
$taskRunner = new taskEngine($injectedObj, $dbObj);
$taskRunner->task1()->task2();
$taskRunner->finish();
//etc
Updated Solution
It is as simple as djechelon's answer suggested, I was overthinking it. The solution is to create a PHPUnit test and pre-assign the variables passed into the taskRunner to mock objects. In the live script, a simple check before creating real objects allows the same script to be used for testing and production:
test:
$injectedObj = $this->getMock('injectedClass');
$dbObj = $this->getMock('DBClass');
require_once '/path/to/live/script.php';
$this->assertTrue($taskRunner->finished);
script:
// require classes
if(!isset($injectedObj)) {
$injectedObj = new injectedClass;
}
if(!isset($dbObj)) {
$dbObj = new DBClass;
}
$taskRunner = new taskEngine($injectedObj, $dbObj);
// run tasks
Can't you create a PHPUnit test for your script?
You could perform an integration test by hand, creating a script that runs your script with a set of given input parameters and compare its output to what you could expect.
Beware of the chicken-and-egg problem: your testing script cannot be tested itself by a test bench...
Anyway I'm not sure you need testing your script if it's so simple. A few manual runs might suffice...

Categories