I try to extend the CheckfrontAPI class with my new class.
In my case I use the Singleton pattern in order to load only one instance at a time of my class and I get that error
Fatal error: Declaration of CheckFrontIntegrator::store() must be compatible with that of CheckfrontAPI::store() in /home/my_web_site/public_html/wp-content/plugins/checkfront/class/Checkfront_Integration.php on line 83
Any idea on how to solve that issue ?
Here is the CheckfrontAPI source code : https://github.com/Checkfront/PHP-SDK/blob/master/lib/CheckfrontAPI.php
And here is my class that extends that class:
<?php
class CheckFrontIntegrator extends CheckfrontAPI
{
private static $instance = null;
public $tmp_file = '.checkfront_oauth';
final protected function store($data = array())
{
$tmp_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR. $this->tmp_file;
if(count($data))
{
file_put_contents(
$tmp_file,
json_encode(
$data,
true
)
);
}
elseif(is_file($tmp_file))
{
$data = json_decode(
trim(
file_get_contents(
$tmp_file
)
),
true
);
}
return $data;
}
public function session($session_id, $data = array())
{
$_SESSION['checkfront']['session_id'] = $session_id;
}
public static function instance($data)
{
if(!isset(self::$instance))
{
self::$instance = new CheckFrontIntegrator($data);
}
return self::$instance;
}
public function __construct($data)
{
if(session_id() == '')
{
session_start();
}
parent::__construct($data, session_id());
}
}
?>
And I initiate the new instance of that class like that:
$this->checkfront_integrator = CheckFrontIntegrator::instance($args);
where args are all the important information needit by the class to initiate a new object
AFTER EDIT
I have change my method store from:
final protected function store($data = array())
....
to
protected function store($data)
....
and the problem still occure :(
CheckfrontAPI is an abstract class? in this case your CheckFrontIntegrator::store() arguments count must be identical to original declaration
EDIT
I see on github
abstract protected function store($data);
your override must be:
protected function store($data) {
}
You are extending CheckfrontAPI. CheckfrontAPI has a method store(). If you override that method you must do it properly.
Post the code of CheckfrontAPI and your class Checkfront_Integration: when can understand what's the problem.
When you want to extent the functionality of an existing class by writing your own class and the class you are extending is is an abstract one, you'll need to make sure that the function calls are compatible.
What does this mean?
If the class you are extending has this function call for example :
function walk($direction, $speed = null);
Then you will have to honor the function signature in your implementation - that means you'll still have to have to pass two function arguments in your version.
You will not be able to alter is to be like this :
function walk($direction, $speed, $clothing);
Related
I'm trying to modify the plugin function in the original PHP class named My_Widget_Admin which i have copied over from a plugin to my theme, but get Fatal error Too few arguments to function My_Widget_Admin
Here is the code i added in my theme :
class Custom_Admin extends My_Widget_Admin {
function item_select() {
// Code
}
}
$new = new Custom_Admin;
$new->item_select();
I think it has something to do with this code from the plugin :
private $_instance;
private $_widget_object;
function __construct( $instance, $widget_object ) {
$this->_instance = $instance;
$this->_widget_object = $widget_object;
$this->form();
}
I need to pass these 2 arguments $instance, $widget_object to the new function Custom_Admin.
How do i do that?
Passing arguments to a constructor must be done when the class gets instantiated. This is done with the new keyword.
class Custom_Admin extends My_Widget_Admin {
function item_select() {
// Code
}
}
$new = new Custom_Admin($instance, $widget_object);
$new->item_select();
I'm trying to create my first phpunit test and find myself needing to stub a method on an IMailer interface.
interface IMailer
{
public function send($to, $from, $cc, $subject, $body);
public function sent();
}
$mailer = $this->getMockBuilder(
'IMailer',
array('send', 'sent'))->getMock();
$mailer->method('send')->willRreturn(0);
However, I keep getting
PHP Fatal error:
Call to undefined method Mock_Mailer_13fc0a04::method()
in ...Test.php on line 16
a var_dump($mailer); results in
class Mock_IMailer_4c3e02a7#215 (1) {
private $__phpunit_invocationMocker =>
NULL
}
Working with the expect($this->any()) gives a dito error - it seems that the mocked object does not have any mock functionality...
I'm running phpunit 3.7.28, and php 5.5.9, on an ubuntu box.
How come? How can I fix it?
The getMockBuilder function accepts only the className as parameter. The correct way to initialize your mock object methods would be to use setMethods function (see phpunit docs)
$mailer = $this->getMockBuilder('IMailer')
->setMethods(array('send', 'sent'))
->getMock();
Additionally you probably want to have some expects definition also when you use your mock object:
$mailer->expects($this->any())
->method('send')
->willReturn(0);
EDIT
The above holds true for newer phpunit versions. For phpunit 3.7.28 the mock object usage is a bit different (i.e. the expects seems to be mandatory and willReturn is not yet available). For 3.7.28 version you should modify the second part to:
$mailer->expects($this->any())
->method('send')
->will($this->returnValue(0));
I would recommend updating to later phpunit version as it seems to be somewhat difficult to find documentation to this much older releases.
An alternative solution, for anybody that is still using old versions of PHPUnit, but still wants to be able to call method() directly, is to override the default mock object class template.
Copy MockObject/Generator/mocked_class.tpl.dist, and name the copy mocked_class.tpl. Then, just add the code for the method() method to the template:
public function method()
{
$any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
$expects = $this->expects($any);
$args = func_get_args();
return call_user_func_array(array($expects, 'method'), $args);
}
This will allow you to call $mock->method() directly. However, you need to still use ->will($this->returnValue(0)) instead of ->willReturn(0). To do that, you need to introduce a custom invocation builder and invocation mocker:
class My_MockObject_Builder_InvocationMocker
extends PHPUnit_Framework_MockObject_Builder_InvocationMocker {
public function willReturn( $value ) {
return $this->will( new PHPUnit_Framework_MockObject_Stub_Return( $value ) );
}
}
class My_MockObject_InvocationMocker
extends PHPUnit_Framework_MockObject_InvocationMocker {
public function expects( PHPUnit_Framework_MockObject_Matcher_Invocation $matcher ) {
return new My_MockObject_Builder_InvocationMocker($this, $matcher);
}
}
And update your template again, to use My_MockObject_InvocationMocker instead of PHPUnit_Framework_MockObject_InvocationMocker.
The full template would then look like this:
{prologue}{class_declaration}
{
protected static $staticInvocationMocker;
protected $invocationMocker;
{clone}{mocked_methods}
public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
{
return $this->__phpunit_getInvocationMocker()->expects($matcher);
}
public function method()
{
$any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
$expects = $this->expects($any);
$args = func_get_args();
return call_user_func_array(array($expects, 'method'), $args );
}
public static function staticExpects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
{
return self::__phpunit_getStaticInvocationMocker()->expects($matcher);
}
public function __phpunit_getInvocationMocker()
{
if ($this->invocationMocker === NULL) {
$this->invocationMocker = new My_MockObject_InvocationMocker;
}
return $this->invocationMocker;
}
public static function __phpunit_getStaticInvocationMocker()
{
if (self::$staticInvocationMocker === NULL) {
self::$staticInvocationMocker = new My_MockObject_InvocationMocker;
}
return self::$staticInvocationMocker;
}
public function __phpunit_hasMatchers()
{
return self::__phpunit_getStaticInvocationMocker()->hasMatchers() ||
$this->__phpunit_getInvocationMocker()->hasMatchers();
}
public function __phpunit_verify()
{
self::__phpunit_getStaticInvocationMocker()->verify();
$this->__phpunit_getInvocationMocker()->verify();
}
public function __phpunit_cleanup()
{
self::$staticInvocationMocker = NULL;
$this->invocationMocker = NULL;
}
}{epilogue}
We have class A and class B.
class B have a public property $class_a.
few functions few functions of class B can set $this->class_a = new A(__METHOD__);
I need to know value of Class B __METHOD__ inside class A.
Now I'm using inside class A:
public function __construct($owner_method){
//some code..
}
is it possible not to pass this parameter during construct?
Is it possible to access such constants of "class owner" when I'm inside that class A ?
I think you need to pass it as you are currently doing. get_parent_class exists but that is for when you are extending objects, which you are not doing, so passing it seems not only the only option but also more proper and reusable to me.
In short: no, you need to carry on passing it in, whether in the constructor or the individual log method.
Personally I think that better solution would be to instantiate that "logging system" class once, pass it to other classes as an argument (DI) and then on each logging action you can can use some method to do the job. That way you have clean __construct.
class A
{
public function __construct() {
}
public function log($owner_method) {
//job
}
}
There is no way to know which class instantiated class A, well, maybe, by parsing stacktrace - but thats odd.
This is my class For writing logs:
class Dll_Log {
protected $data = array();
protected $function = NULL;
private $path = FALSE;
public function __construct($function){
$function = str_replace('::','-',$function);
$this->function = $function;
$this->path = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'log'.DIRECTORY_SEPARATOR;
}
public function set($data){
$this->data = array_merge((array)$this->data, (array)$data);
return $this;
}
public function __destruct(){
if(WRITE_LOG AND (count($this->data)>0)){
$this->data = array('data'=>$this->data, 'time'=>date("H:i:s"));
$file = $this->path.date("Y-m-d").DIRECTORY_SEPARATOR.$this->function;
$dirname = dirname($file);
if (!is_dir($dirname)){
mkdir($dirname, 0755, true);
}
$f = fopen ($file, 'a+' );
flock ( $f, LOCK_EX );
fwrite($f,json_encode($this->data).PHP_EOL);
flock ( $f, LOCK_UN );
fclose ( $f );
}
}
So when I'm debugging some classes For example class B, method load_page:
I must to do next:
Class B{
public function load_page(){
$logger = New Dll_Log(__METHOD__);
if( ($x = do_something()) !==false)
$logger->set(array('x-val-problem'=>'$x received FALSE value'));
if( ($y = do_something_other()) !==false)
$logger->set(array('y-val-problem'=>'$y received FALSE value'));
if( ($z = do_something_else()) !==false)
$logger->set(array('z-val-problem'=>'$z received FALSE value'));
try{
SomeClass::SomeMethod($x,$y,$z);
}catch(Exception $e){
$logger->set(array('GOT_EXCEPTION'=>$e));
}
}
}
AS you see, each time when I $logger = New Dll_Log(__METHOD__); - it's little not comfortable. $logger = New Dll_Log(); will be eaiser and it can guarantee that third-party classes will not able to falsificate LOG data..
Will be great if php have get_owner_class, not only get_parent_class.. :(
OK. here is what I'm trying to do:
class Image{
public $_image;
public $_extension;
public $_mime;
public $_size;
public $_location;
public $_description;
public function __construct($image, $location){
$this->_image = $image;
$this->_location = $location;
$this->_extension = getExtension();
$this->_mime = getMime();
$this->_size = getSize();
}
private functions fallow.....
}
But I keep getting an internal server error when I try to run it. When I comment out the method calls it works. So the question is can I call methods from inside the constructor or am I doing something wrong with the methods.
Do your functions getExtension, getMime and getSize exist? Are they methods on this class? If they are methods, they need to be called with $this->... as in
$this->_extension = $this->getExtension();
If they are not methods, and are functions, you need to make sure the files that contain/define them are loaded before you run the constructor.
Well ..this fragment of code will work as expected:
class Foo
{
protected $secret = null;
public function __construct( $data )
{
$this->secret = $this->makeSecret($data);
}
public function makeSecret( $data )
{
return md5( $data );
}
}
$bar = new Foo( 'lorem ipsum' );
That is not a problem.
But you should know, that is considered to be a bad practice - to do computation/work in the constructor. It makes that class practically untestable. Instead, if you need to perform some computation before "releasing" the object to the rest of the code, you should use a factory. Something along the lines of :
class ImageFactory
{
public function build($image, $location)
{
$instance = new Image($image, $location);
$instance->prepare();
return $instance;
}
}
The class would need some changes:
class Image
{
protected $_image; // you were leaking abstraction
protected $_extension;
protected $_mime;
protected $_size;
protected $_location;
protected $_description;
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
}
public function prepare()
{
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
private functions fallow.....
}
Now when you need to create new object you do:
$factory = new ImageFactory;
$image = $factory->build( $file, '/uploads/' );
Of course the instance of ImageFactory can be reusable, and if all your images use the same $location, then you would pass that variable to factory at the initialization. And the factory would be able to "remember it" and pass to all the images it creates:
$factory = new ImageFactory('/uploads/');
$img1 = $factory->build( $file );
$img2 = $factory->build( $something_else );
This is actually how one should deal with creating multiple objects, which all need access to same DB connection instance.
Yes, you can call methods from within the constructor. Remember that the __construct() magic method was implemented in PHP 5. Prior to that, you created a function named the same as your class which acted as your constructor so depending on your PHP version, that could be a problem.
Additionally, the function calls you are making, are they in the class or external? If they are inside the class you need to call them this way:
$this->_extension = $this->getExtension();
You didnt specified what error you are expiriencing clearly. But try calling you class methods even inside the class using this keyword, otherwise it would not work:
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
Would be a better idea to post your code for the methods you wrote. There could be something wrong within them as well. Possibly forgetting to return a result or something...
Writing unit tests for code which is already written is fun sometimes.
I am writing a test case for the following code (an example):
<?php
class mockPrivate {
public static function one($a){
$var = static::_two($a);
return $var;
}
private static function _two($a){
return $a+1;
}
}
?>
The test class is like this:
<?php
require_once 'mockPvt.php';
class mockPrivate_test extends PHPUnit_Framework_TestCase {
public $classMock;
protected function setUp(){
$this->classMock = $this->getMock('mockPrivate', array('_two'));
}
public function test_one(){
$a = 1;
$retVal = 2;
$classmock = $this->classMock;
$classmock::staticExpects($this->once())
->method('_two')
->with($a)
->will($this->returnValue($retVal));
$value = $classmock::one($a);
$this->assertEquals($value, $retVal);
}
}
?>
After running by $ phpunit mockPrivate_test.php I got this error:
PHP Fatal error: Call to private method Mock_mockPrivate_531a1619::_two() from context 'mockPrivate' in /data/www/dev-sumit/tests/example
s/mockPvt.php on line 6
But if I change the
private static function _two()
to
public static function _two() or
protected static function _two()
it works totally fine. Since this is a legacy code I can't change the private to public/protected. So is there any way I can test the function one or Is this a limitation of phpunit?
Another option is to create a class that extends mockPrivate, allowing accessibility to the object you wish to test. Your engineers should be thinking long and hard about why something is private (because that means the class is not easily extensible). Also remember that you can mock the test class if you need to override what it returns.
class Test_MockPrivate extends MockPrivate
{
/**
* Allow public access to normally protected function
*/
public static function _two($a){
return parent::_two($a);
}
}
// Code to force the return value of a now public function
$mock = $this->getMock('Test_MockPrivate', array('_two'));
$mock->expects($this->any())
->method('_two')
->will($this->returnValue('Some Overridden Value');
You can use reflection for changing visibility of methods. You can find more info in
PHP object, how to reference?
Use mock and reflection... (posted this solution, since this is the top google result)
$oMock = $this->getMock("Your_class", array('methodToOverride'));
$oMock->expects( $this->any() )
->method('methodToOverride')
->will( $this->returnValue( true ) );
$oReflection = new ReflectionClass("Your_Class");
$oMethod = $oReflection->getMethod('privateMethodToInvoke');
$oMethod->setAccessible( true );
$oMethod->invoke( $oMock );