I'm struggling to get my Behavior class to use an object instance in the callbacks.
class SomethingBehavior extends ModelBehavior
{
public function setObject($obj)
{
// do stuff
}
public function afterFind(Model $model,$results,$primary)
{
// use the $obj reference set above
}
}
Now I need the Model class to call setObject(..) before any find operations are performed. So ideally I would just assign the object I need in the constructor.
class Document extends AppModel
{
//.....
public function __construct($id,$table,$ids)
{
parent::__construct($id,$table,$ds);
$this->Something->setObject(new MyClass());
}
}
My problem is that the Behavior object isn't yet configured, and I get a not an object error when trying to use it.
I can't find any callback method for Models like in Components. For example, there is no setup or initialize method.
How can I assign the object I need to the Behavior?
You don't seem to have worked with behaviors much. Try to use the containable, tree or other core or plugin behaviors, then you will soon figure out the basics.
First of all, behaviors are attached to models (and since 2.3: loaded), not the other way around. A model then gets "richer" in functionality.
Either statically be using public $actsAs or dynamically using
$this->Behaviors->attach('Something'); // since 2.3: load() instead of attach()
It can directly access the behavior methods. Lets say we have a method foo() in your behavior.
You can then call it from your model as
$this->foo($foo, $bar);
Or from your controller as
$this->Document->Behaviors->attach('Something')
$this->Document->foo($foo, $bar);
Awesome, right?
The behavior method usually has this declaration:
public function foo(Model $Model, $foo, $bar) {
$alias = $Model->alias;
// do sth
}
As you can see, you always pass the model into it implicitly (as first argument automatically passed).
You can access all its attributes.
And do not touch the constructor of the model. no need to do that.
If you really need to pass an object in at runtime, why does your approach not work?
public function setObject(MyClass $obj) {
$this->Obj = $obj;
}
Now you can internally use the object from your behavior methods
public function doSth(Model $Model) {
$this->Obj->xyz();
}
Also this might not be the most elegant approach.
You never set the something member of the Document class. You either need to instantiate it inside the constructor, or pass it in.
Personally, I would do something like this:
class Document extends AppModel
{
private $behavior;
public function __construct($id,$table,$ids, ModelBehavior $behavior)
{
parent::__construct($id,$table,$ds);
$this->behavior = $behavior
$this->behavior->setObject(new MyClass());
}
}
$doc = new Document(..., new SomethingBehavior());
Or better yet, you could even separate it further by doing:
class Document extends AppModel
{
private $behavior;
public function __construct($id,$table,$ids, ModelBehavior $behavior)
{
parent::__construct($id,$table,$ds);
$this->behavior = $behavior
}
}
$behavior = new SomethingBehavior();
$behavior->setObject(new MyClass());
$doc = new Document(..., $behavior);
That way, there is less magic going on in the constructor.
Related
Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.
i have to test class add_Hook
class add_Hook extends Hooks_base
i tried to create a mock of hooks_base like this:
> $this->oHookBaseMock = $this->getMock(
> 'Hooks_base',
> array('get_database','get_arguments'),
> array(null,'null') //this are the parameters for the constructor
> );
$this->hook->expects($this->any())
->method('get_database')
->will( $this->returnValue(true)
);
$this->hook->expects($this->any())
->method('get_arguments')
->will( $this->returnValue($arraySImpleXmlObject)
);
and doing something like this :
$hook = new add_Hook($this->hook)
And now my problem is that when i run the test it steels ask me for the 2 parameters of the parent class (hooks_base)
the constructor is something like this
public function __construct($parameter_1, $parameter_2) {
$this->_param1 = $parameter_1;
$this->_param2 = $parameter_2;
}
i dont' know how to disable the constructor of the parent class and if i do it.
I simply create an instance of the abstract class in my test. $Object = new ABSTRACT_CLASS() and have no code in the definition of the methods that need defined as I do not intend to test the abstract method.
class TestAbstractInput extends AbstractInput
{
public ImplementAbstractFunction()
{ // Purposely empty so nothing happens. This would be defined in normal class extending AbstractInput
}
...
}
class AbstractInputTest extends TestCase
{
// ...
public function setUp()
{
$this->TestClassObject = new TestAbstractInput();
}
public function test_isValid()
{
$this->assertEquals(1, $this->TestClassObject->isValid);
}
}
This way the individual methods may be tested. Then I test the normal class that usually extends the abstract class to test the functions that were implemented in that class.
class InputTest extends TestCase
{
// ...
public function setUp()
{
$this->TestClassObject = new AbstractInput();
}
// Parent function should still work
public function test_isValid()
{
$this->assertEquals(1, $this->TestClassObject->isValid);
}
public function test_ImplementAbstractFunction()
{
$this->assertTrue($this->AbstractFunction());
...
}
}
EDIT There is also the built in getMockForAbstractClass() which may work directly for you if you are using a new enough version. You can also instruct Mocks to not run the constructor.
You can't "mock" the parent class of your class. You could create a mock of your class and replace the parent methods that you are wanting to replace.
$add_hook = $this->getMock('add_Hook',
//This will mock these methods only and leave the rest untouched provided the class is able to be loaded.
array('get_database','get_arguments'),
array(param1, param2));
$this->hook->expects($this->any())
->method('get_database')
->will( $this->returnValue(true)
);
$this->hook->expects($this->any())
->method('get_arguments')
->will( $this->returnValue($arraySImpleXmlObject)
);
Your attempt was to somehow inject the parent into class. The class is an instance of the parent so you can't "mock" it without mocking the class itself.
In my opinion, this is not a good practice. You are testing the implementation of your class rather than testing the behavior of your class. Your test should rather check what your method does rather than how it does it. What is that 'get_database' and 'get_arguments' do? Perhaps you should be passing an instance of 'Hooks_base' into your class rather than extending it.
From what you have posted my test would look like:
public function testInit() {
$param1 = <what ever the argument needs to be>;
$param2 = <something else>;
$addHook = new add_Hook($param1, $param2);
$this->assertInstanceOf('Hooks_base', $addHook); //I would probably have this in a constructor test
$addHook->init();
//Assertions for what init() does
}
I wonder if I can make controllers implementing some methods no matters if that method will be public, private or protected and if it will have any parameter. I just want to ensure, that controller has method with specified name, no more.
For example:
interface SomeInterface {
function someFunction();
function someOtherFunction();
}
class SomeController extends SomeBaseController implements SomeInterface {
//some action
public function someAction() { ... }
//an implementation of SomeInterface method
public function someFunction() { ... }
//an implementation of SomeInterface method
protected function someOtherFunction($someParameter) { ... }
}
I know that it's not possible to do this with ordinary php interfaces but maybe there is some other way in php or maybe symfony2 has some tool to accomplish this?
I know of one way to do this, which relies on the __call() method available in PHP: http://www.php.net/manual/en/language.oop5.overloading.php#object.call
__call() is triggered when invoking inaccessible methods in an object context.
You could go ahead and create a parent class that looks like this - although it's not an Interface, so take care if you need it outside a single domain.
class BaseClass{
public function __call($name, $arguments) {
$methodsToImplement = array(
'method1', 'method2', 'method3'
);
if (in_array($name, $methodsToImplement)) {
throw new Exception("Method " . $name . " is not yet implemented.");
}
}
}
It seems there is no way to accomplish this. So I mark my question as reslolved, however if someone knows an answer let me know! :)
This might be basic knowledge, but I am curious as I do not know it yet myself. Why in PHP (and assuredly other languages) when using classes must a child class use a construct method to access the parent class' properties. In case this is unclear I will include an example.
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty;
public function __construct()
{
$this->$aDifferentProperty = $this->aProperty;
}
?>//Works.
Instead of:
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty = $this->$aProperty;
}
?>//Doesn't work.
Its not a matter of needing the constructor its a matter of WHEN you're trying to access it. A class is a blueprint for an object -- when you're trying to assign the property, as you've done in your example above, ie.
public $aDifferentProperty = $this->aProperty;
There is no object, and thus "this" does not yet exist. But, instead, this would work:
class A {
protected $a_property = "BOOYEA!";
}
class B extends A {
public function show_me_a_prop() {
echo $this->a_property;
}
}
$object = new B();
$object->show_me_a_prop();
So, to answer your question, you must wait until after the object has been constructed to access the properties because until its constructed, its not an object, just a blueprint for an object.
Now, to take this a bit further, you'd not allowed to assign variables directly to properties (see http://php.net/manual/en/language.oop5.properties.php ) but you can assign a constant. So here's a similar example which does work:
class A {
const a_property = "BOOYEA!";
}
class B extends A {
public $b_property = self::a_property;
}
$object = new B();
echo $object->b_property;
The "__construct" was introduced in PHP5 and it is the right way to define your constructors (in PHP4 you used the name of the class for a constructor).
You are NOT REQUIRED to define a constructor in your class, but if you wish to pass any parameters on object construction THEN YOU NEED ONE.
Also...If further down the track you change the class the child class inherits from, you don't have to change the construct call to the parent.
much easier to call parent::__construct() instead of parent::ClassName(), as it is reusable among classes and the parent can be changed easily.
In a base class for all the models in our MVC system, I created a factory method BaseCLass::getNew() that returns an instance of the requested child class when called via SomeChildClass::getNew().
Now, I'm looking for a way to force the programmer to use this factory. I.e., idially I'd like that any class created directly, like this:
new SomeChildClass
will throw an exception upon creation, and only classes created by the factory will be usable.
Any ideas how can this be achieved?
Our code is written in PHP, but good chance that your idea will be valuable even if you think on a different language.
edit: I cannot make my constructor private, as the framework constructor in the class that I inherit is public, and php would not allow me this.
By making the constructor of the child class protected. The parent class will have access to all protected methods of the child. Any attempt to directly create the child (ie: new child) will cause a fatal error.
<?php
class factory
{
static public function create()
{
return new child;
}
}
class child extends factory
{
protected function __construct()
{
echo 'Ok';
}
}
$c = factory::create(); // Ok
$c2 = new child; // fatal error
?>
Though this method won't let you throw an exception instead :(
If then absolutely necessary, only debug_backtrace() function comes to mind (besides using singleton for the child itself, or forced object pool patterns using and passing GUID's generated by factory and verified by child). Within the child constructor, look at the 2nd array value to make sure "function" === "create" and "class" === "factory. Throw exception if not matching. I didn't suggest this initially, only because I suspect using debug_backtrace may give a performance hit.
By making the class have a private constructor.
Update -- solution that covers your stated requirements
class Base {
private static $constructorToken = null;
protected static function getConstructorToken() {
if (self::$constructorToken === null) {
self::$constructorToken = new stdClass;
}
return self::$constructorToken;
}
}
class Derived extends Base {
public function __construct($token) {
if ($token !== parent::getConstructorToken()) {
die ("Attempted to construct manually");
}
}
public static function makeMeOne() {
return new Derived(parent::getConstructorToken());
}
}
This solution takes advantage of the object equality rules for stdClass by storing a "magic password" object on the base class which only derived classes can access. You can tweak it to taste.
I wouldn't call it horrible like the debug_backtrace idea, but still I have the impression that things should be done differently.
Declare the class's constructor private, and it can only be called from within the class's own methods like getNew().
there are couple of ways to implement it
make parent class private use magic
user magic function __autoload; check the type of class and through error with not allowed message
http://php.net/manual/en/function.is-a.php
The best way is to define constructor of the class private or protected. But if you cannot do it, you can control where an object of the class is created in the constructor:
trait FactoryChecking
{
protected function checkFactory(string $factoryClass): void
{
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach($trace as $traceItem) {
if ($traceItem['class'] == $factoryClass) {
return;
}
}
throw new Exception('Cannot create class ' . static::class . ' outside of factory');
}
}
class ClassA
{
use FactoryChecking;
public function __construct()
{
$this->checkFactory(Factory::class);
}
}
class Factory
{
public function create(): ClassA
{
return new ClassA();
}
}
Details I described in the article "Forbidding of creating objects outside factory in PHP"