Supposing I have a trait which currently has a method:
trait MyTrait
{
public function traitMethod()
{
return true;
}
}
Now let's say this trait is used by several classes but I don't want to write a unit-test for every class.
Instead I want to write a single unit-test only for the trait:
public function testTraitMethod()
{
$trait = $this->getMockForTrait(MyTrait::class);
$this->assertTrue($trait->traitMethod());
}
But the problem is that a class may actually override trait's method:
class MyClass
{
use MyTrait;
public function traitMethod()
{
return false;
}
}
In this case MyClass is doing something wrong but I'm not aware of it since I'm testing only the trait.
My idea would be write a single unit-test for every class just to check if it's using that trait and it's not overriding that method. If a class needs to override trait's method then it needs a specific unit-test as well.
Currently I'm writing unit-tests for each class that implements my trait but it's of course kind of copy-paste tests everywhere.
So is there a way to test if a class calls it's underlying trait method?
I found a solution using Reflection, I'll post it in case someone needs it because I couldn't find anything related to my problem. Feel free to comment or add different solutions if you want.
So the following test asserts that $serviceClass uses $traitClass and doesn't override methods declared in $traitClass except abstract ones and those which are manually added to $overriddenMethods array.
public function testServiceUsesTrait()
{
$serviceClass = MyClass::class;
$traitClass = MyTrait::class;
$this->assertContains($traitClass, (new \ReflectionClass($serviceClass))->getTraitNames());
$reflectedTrait = new \ReflectionClass($traitClass);
$reflectedTraitFile = $reflectedTrait->getFileName();
/**
* If $serviceClass overrides some trait methods they
* should be inserted into this array to avoid test failure.
* Additional unit-tests should be written for overridden methods.
*/
$overriddenMethods = [];
foreach ($reflectedTrait->getMethods() as $traitMethod) {
if ($traitMethod->isAbstract() || in_array($traitMethod->getName(), $overriddenMethods, true)) {
continue;
}
$classMethod = new \ReflectionMethod($serviceClass, $traitMethod->getName());
$this->assertSame($reflectedTraitFile, $classMethod->getFileName(), sprintf(
'Trait method "%s" is overridden in class "%s" thus it must be excluded from this test.',
$traitMethod->getName(), $serviceClass
));
}
}
I also tried to compare declaring classes using $classMethod->getDeclaringClass() instead of comparing filenames but it didn't work: even if trait method is not overridden in class, getDeclaringClass() always returns the class itself.
Related
I'm working with Laravel 5.8 and it's an Online Store project written by other programmers.
Basically I have faced something weird that never seen before.
Let's say we have this at a Controller method:
$payment = CourseRegistrationFacade::insertCourseRegisterInformation($courseId,$date,$memberId,$userId);
And then we goto the CourseRegistrationFacade and it goes like this:
class CourseRegistrationFacade extends BaseFacade
{
}
So the whole class is empty but it extends another Facade which is BaseFacade and it goes like this:
class BaseFacade extends Facade
{
protected static function getFacadeAccessor()
{
return static::class;
}
protected static function shouldProxyTo($class)
{
app()->bind(self::getFacadeAccessor(), $class)
}
}
And that's it !
I don't really know where the heal is insertCourseRegisterInformation !!
So if you know how this Facade works, please let me know...
Here is the full code of BaseFacade.php:
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class BaseFacade extends Facade
{
protected static function getFacadeAccessor()
{
return static::class;
}
public static function shouldProxyTo($class)
{
app()->bind(self::getFacadeAccessor(), $class);
}
}
Search in the code for:
CourseRegistrationFacade::shouldProxyTo(
Most likely in the service provider that line is somewhere registering that facade to some concrete implementation of a class. Then check the contents of the class (the argument passed to shouldProxyTo).
Inside that class there should be a method called insertCourseRegisterInformation.
The way facades work is they resolve the class out of the container and then call the method you call statically.
So for example, let's say you have a UserService.php with a method register() and that class is mapped to a UserServiceFacade.php. When you do UserServiceFacade::register(), __callStatic will get the facade accessor (actual class) from the container, then call the register() method of that class.
You can understand better by inspecting __callStatic inside Facade.php.
Essentially UserServiceFacade::register() is the same as doing:
$userService = app()->make(UserService::class);
$userService->register()
By using the facade you can hide the concrete implementation and could possibly switch it to something else in the future by just changing it in a single place.
I think there must be a Provider exists for that Facade which is initializing its associated class and insertCourseRegisterInformation method definition must be declared in it. Please find that provider and then you'll find its associated class from that Provider code. I think you can find all registered providers from config/app.php
These reference articles might help you.
Reference 1:
https://grafxflow.co.uk/blog/mvc/adding-global-custom-class-facades-laravel-5
Reference 2: http://www.expertphp.in/article/how-to-create-custom-facade-in-laravel-52
I am currently on PHPUnit v5.7.27
I would like to create a mock object that uses an array of traits. How would I go about this? I only see getMockForTrait as a way to create a mock object using a single trait. My issue is that the trait requires the existence of another trait at the class level.
Update: More context to the issue
Given:
trait GetSet {
public function __call(){ /* does some magic */
}
trait RepositoryAware {
public function getRepository(string $name)
{
/* makes use of the GetSetTrait*/
}
}
class Controller
{
use GetSet;
use RepositoryAware;
}
Given the limitations of PHP, I can not simply put a use GetSet on the RepositoryAware trait because other traits that the controller imports could also bring the GetSet trait. Furhtermore, the controller class itself could be using the behavior provided by the GetSet trait.
The current solution I have is to create a Dummy Class that imports both traits and mock that class instead:
class RepositoryAwareClass
{
use GetSet;
use RepositoryAware;
}
Like this I am able to properly test the behavior provided by the RepositoryAware trait while at the same time composing its requirement of the GetSet trait.
Mocking concept was built with the idea that you would be using dependency injection. I can certainly see why you may not want to use dependency injection with this multiple inheritance like model that php uses called "Traits". Mocking tools like the one built for phpunit was built to substitute instances of objects not classes/interfaces/traits themselves. PHP Traits are more like having a static dependency instead of a dependency on an instance of an object. However, even if you were using traits and assuming a trait was basically the same as a class, according to mocking best practices should test the trait as its own test instead of testing a trait through another class. If you want to mock the trait itself you may want to try to revisit your design as I do not believe it can be done. You can certainly mock a trait and test that trait but you cannot mock a trait and then inject it as a dependency on an object. Imagine that a class for example implements an interface, mocking a trait would be the same a mocking an interface that a class implements, its not possible. You can only mock an interface of an object that a class depends upon through setter or constructor based dependency injection. Another example would be to try and mock the class that the class under test inherits from. You can't do that either. Perhaps in the javascript world this type of thing could be useful and from some people's point of view desired, but I think if you want to use mocking you would need to stick with object dependency injection instead of static use of traits.
So what's the alternative? I think the following example would be how to use perhaps "traditional" OOP practices with mocking to achieve your goal of sharing functionality without using inheritance. The example also makes your dependencies more explicit. And for the record, I applaud you for NOT using inheritance.
<?php
interface GetterSetter {
public function __call();
}
interface RepositoryProvider {
public function getRepository(string $name);
}
class GetSet implements GetterSetter {
public function __call() {
/* does some magic */
}
}
class DefaultRepository implements RepositoryProvider, GetterSetter {
/**
* #var GetterSetter
*/
private $_getterSetter;
public function __construct(GetterSetter $getterSetter) {
$this->_getterSetter = $getterSetter;
}
public function getRepository(string $name) {
// makes use of the GetSetTrait
$this->__call();
}
public function __call() {
// makes use of the GetSetTrait
$this->_getterSetter->__call();
}
}
class Controller implements RepositoryProvider, GetterSetter {
/**
* #var RepositoryProvider
*/
private $repositoryProvider;
public function __construct() {
$this->repositoryProvider = new DefaultRepository(new GetSet());
}
public function getRepository(string $name) {
return $this->repositoryProvider->getRepository($name);
}
public function __call() {
$this->repositoryProvider->__call();
}
}
In general I feel like the PHP community took a wild left turn, trying to be more like javascript and I feel that traits can walk you into a corner. This is a very good example of such a corner. I would really avoid them, at least for now. In the long run I believe Generics would be the better solution to your problem of needing a generic GetSet piece of code but generics haven't been implemented in php yet :-(.
I currently have an abstract class which i am extending to other controllers. I have a abstract function within the abstract class which takes the value and places it in the __construct.
abstract class Controller extends BaseController {
abstract public function something();
public function __construct(Request $request) {
if (!is_null($this->something())){
$this->global_constructor_usse = $this->something();
}
}
}
My problem is that, on controllers that don't require this abstract function, I am having to place in the empty function.
class ControllerExample extends Controller {
public function something(){
return 'somethinghere';
}
}
Is there anyway to making the abstract function optional, or have a default value?
class EmptyControllerExample extends Controller {
public function something(){}
}
It is not possible to have a abstract method optional, as it is implied in PHP that all abstract methods must have an implementation.
There are legit use cases for optional abstract methods, yes: event handlers, metadata describers, etc. Unfortunately, you'll need to use regular, non-abstract methods with an empty body, and indicate in PHPDoc that they will do nothing unless extended.
Be wary, though: this can very quickly turn into code smell by diffusing a class responsability with their children. If you're dealing with generic events, you can look into Laravel's own event system, or the Observer pattern instead.
Abstract functions in a parent class, should only be used if its required by your application to implement the following method in all controllers who inherits from it, clearly it is not the case.
In this case i would make a trait. Here you create a trait which can be implemented by the classes who needs it. Notice the use keyword usage, use somethingTrait;
trait SomethingTrait
{
public function something()
{
echo "something called";
}
}
class Controller
{
use SomethingTrait;
public function run()
{
$this->something();
}
}
phpfiddle link
Another aproach could be doing a class inheritance structure, if the controllers you want to implement the methods has something in common. Where you would implement your special method in CrmController, where you still would be able to create shared methods in the abstract controller.
AbstractController
|
CrmController
|
CompanyController
For your question, 'Is there anyway to making the abstract function optional or have a default value?' No, and you are down the wrong path if you are trying to make abstract function optional. Hope my suggestions can help.
This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.
From the past two days i have been diving into the concepts of OOPS in PHP, and i found Abstract Class to be very useful concept and i wanted to implement it in my application. and here is why i want to implement it.
My Application Consist of Several Unstructured Pattern which uses several different classes without any hierarchies, due to this i have to use several repeated codes. i want to cut this all up and structure it properly, basically what i want to do is
Define a parent class which is not instantiable from outside.
Define all properties in this parent class so that i can re-use the same property for different child classes.
Define re-usable class methods and objects so that child class can use it without the need of defining it again and again (Inheritance).
Basically My Abstract class should be capable of inheriting the re-usable methods and properties and at the same time it should act as an Interface.
To demonstrate you clearly let me show you some sample codes which i have been using.
public $error = array(); //used to handle error mechanism and to hold the errors.
private $data = array(); //used with Accessor Methods (__set and __get)
private $validate; //holds Validate Object
private $dbh; //holds Database Object
public function __set($property, $value) {
if( in_array($property, $this->data)) {
return $this->data[$property] = $value;
} else {
return false;
}
}
public function __get($property) {
return 'Access Denied to Class Property [ '.$property.' ]';
}
Above codes are repeated for almost every class, this is the reason i want to define it once in a parent class and control the mechanism from there.
As i am still Novice to Many OOPs concept i am unable to understand how do i achieve what i want using Abstract Class. below is the sample code i tried using which ofcourse is wrong for declaring an abstract method.
abstract class Property {
protected $error = array();
protected $data = array();
protected $dbh;
protected $validate;
abstract protected function connectDB($dbhandle) {
return $this->dbh = $dbhandle;
}
abstract protected function setValObj($valObj) {
return $this->validate = $valObj;
}
public function __set($property, $value) {
}
public function __get($property) {
}
}
here is what i want to do.
When a child class is initiated it should be forced to define methods as declared in abstract class.
A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
i know i am missing something, or might be i have not got the concept right, could somebody explain me what exactly should i be doing to achieve the same result.
1 . Define a parent class which is not instantiable from outside.
All abstract classes can not be instantiated, only extended. So this is what you already have:
abstract class Property {
On to the next:
2 . Define all properties in this parent class so that i can re-use the same property for different child classes.
Just write them into that abstract class (often called base class or abstract base class or template class as well). All classes extending from a base class, will have access to protected or public member methods and properties. If you make a variable or function private, it's only available to code in the base class.
So just define all you want to have in the base class to be shared amongst all extending classes and you only need to type it once.
3 . Define re-usable class methods and objects so that child class can use it without the need of calling it again and again (Inheritance).
This works automatically. As you extend from the base class, the public and protected class methods defined therein are automatically accessible through the extending class. You do not (but you can unless specified with final) need to add that function again to make it available. E.g. all public methods from the base class are automatically available publicly on all classes that extend from it.
Then you continue:
here is what i want to do.
1 . When a child class is initiated it should be forced to define methods as declared in abstract class.
You can do so by defining these needed methods as abstract. Abstract methods needs to be implemented by the extending class. However you can not put code into abstract methods in the base class. That's left there for the extending class.
2 . A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
If you want to prevent a subclass to overwrite a function, declare it as final in your base class. Final methods can not be further extended.
But probably you want to do something that is technically not possible, e.g. prevent that a method can be extended while you require that is should be extended.
In your code you're using magic functions to access the properties / values. Those don't count in the sense that their name changes. So you loose the control of the inheritance for a bigger part of your class design.
However, you can implement array access to offer getter/setters. It's bound to a concrete interface and you then can disallow access through the base class and prevent extending of this area for classes that will extend from it.
Let me know if you would like to have some example code, probably SPL is new to you as well.
Provide variable inheritance via ArrayAccess
As you've been running into the problem that inheritance can not be easily used on the magic function __get() and __set() which are available, I had the idea to make that part of the access concrete that does not change (get, set) while it's still possible to name the property variable. An interface that is available with PHP that already does this is ArrayAccess. It was designed to give access to properties via the style we know from standard php arrays ([]) and it's normally used for that. But for this example it has the benefit to already provide an interface as well that fits the general need.
First a demonstration how such a class behaves in use:
# give birth to the object
$object = new PropertyClass; // one of your property classes
# get:
$value = $object['propertyA'];
# set:
$object['propertyA'] = 'new value';
# unset:
unset($object['propertyA']); // and gone ;)
# isset:
isset($object['propertyA']); // true / false
Okay, as this shows, this looks like an array, but is an object. The rest of $object works as known, so this is no limitation, but an addition.
As you can imagine already with this code, there must be a get and set routine as well for reading and setting the properties values like with __get() and __set(). Additionally there must be something for isset and unset, so four. This is the interface definition of ArrayAccess:
ArrayAccess {
/* Methods */
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}
You can extend from that in PHP by implementing the interface. That's not extends but implements. This works with every interface in PHP, but this interface is something special as well. It's provided by the SPL/PHP itself and in the moment a class of yours actually implement the functions, the functionality as described in the code above is automatically added to your class.
As those functions are available publicly, you could call them with their name as well naturally.
So actually this interface qualifies for a properties object as you want to build one and will give you an interface you can put your constraints on.
So the only question left is: How can this look like for your properties class?
Implementing ArrayAccess to a variable properties class
<?php
/**
* Property Object base class based on ArrayAccess
*/
abstract class PropertyObject implements ArrayAccess
{
/** Interface Methods */
/**
* implementing classes must return all names of their properties
* in form of an array.
*/
abstract protected function returnNames();
/** class */
/**
* value store
*
* #var array
*/
private $store = array();
/**
*
* By this design, properties can only contain A-Z and a-z.
*
* look like.
*
* #return bool
*/
private function isValidPropertyName($name) {
return ctype_alpha($name);
}
private function checkOffsetArgument($offset) {
if ($this->isValidPropertyName($offset)) return;
throw new InvalidArgumentException(sprintf('"%s" is not a valid property name.', $offset));
}
private function setNames(array $names) {
foreach($names as $name) {
$this->checkOffsetArgument($name);
}
$len = count($names);
$this->store = $len
? array_combine($names, array_fill(0, $len, null))
: array()
;
}
/**
* final constructor to obtain control
*/
final public function __construct() {
$this->setNames($this->returnNames());
}
/**
* ArrayAccess impl.
*
* #return bool
*/
public function offsetExists($offset) {
$this->checkOffsetArgument($offset);
return array_key_exists($offset, $this->store);
}
/**
* ArrayAccess impl.
*
* #return mixed
*/
public function offsetGet ($offset) {
$this->checkOffsetArgument($offset);
return $this->store[$offset];
}
/**
* ArrayAccess impl.
*/
public function offsetSet($offset, $value) {
$this->checkOffsetArgument($offset);
if (!$this->offsetExists($offset)) {
throw new InvalidArgumentException(sprintf('Property "%s" can not be set.', $offset));
}
$this->store[$offset] = $value;
}
/**
* ArrayAccess impl.
*/
public function offsetUnset($offset) {
$this->checkOffsetArgument($offset);
unset($this->store[$offset]);
}
}
/**
* I feel so concrete.
*/
class ConcreteType extends PropertyObject
{
protected function returnNames() {
return array('propertyA');
}
}
$obj = new ConcreteType;
var_dump($obj['propertyA']); # NULL, maybe you need other default values.
$obj['propertyA'] = 'hello';
var_dump($obj['propertyA']); # string(5) "hello"
var_dump(isset($obj['propertyA'])); # bool(true)
// this will trigger an exception
try {
$obj['XProperty'] = 'good night.';
} catch (Exception $e) {
var_dump($e->getMessage()); # string(36) "Property "XProperty" can not be set."
}
// the following might be unwanted but can be prevented in base class:
unset($obj['propertyA']);
var_dump(isset($obj['propertyA'])); # bool(false)
I think you need to implement mixin interface. According to my knowledge PHP does not support this natively. Some PHP frameworks (like Yii framework) implemented it by itself. I found one example here. But I am sure you will be able to find better examples.