Create multi entities in Symfony4 Unit tests - php

Since few days, I'm trying to learn Symfony Unit Test.
I made my first test but I noticed one thing :
For my first test, I tested a simple implode for some tags :
class TagsTransformerTest extends TestCase
{
public function testTransform()
{
$tagsArray = [
$this->createTag('Symfony'),
$this->createTag('Test'),
$this->createTag('Unit'),
];
$transformer = $this->getMockedTransformer();
$tagsTransformed = $transformer->transform($tagsArray);
$this->assertEquals('Symfony, Test, Unit', $tagsTransformed);
}
private function getMockedTransformer()
{
$entityManager = $this
->getMockBuilder(ObjectManager::class)
->disableOriginalConstructor()
->getMock();
return new TagsTransformer($entityManager);
}
private function createTag($name)
{
$tag = new Tag();
$tag->setName($name);
return $tag;
}
}
As you can see, I have to create a createTag() method to build some tags, but I wonder if I can like Laravel :
$anakin = factory(User::class)->states('anakin')->create();
$post = factory(Post::class)->create(['author_id' => $anakin->id]);
factory(Post::class, 2)->create();
factory(Comment::class, 3)->create(['post_id' => $post->id]);
My question is, is there any way to use a object like factory in Symfony to avoid going through an alternative method ?

Better:
$tagsTransformed = ($this->getMockedTransformer())->transform($tagsArray);
$this->assertEquals('Symfony, Test, Unit', $tagsTransformed);
Yes i think you can, check this
$form = $this->factory->create(TestedType::class);

Related

refactoring old php with reflection

so I am refactoring some old code written by someone else. I've come across this:
$r = new \ReflectionClass($className);
$args = (is_subclass_of($className, 'ClassA')) ? [$arg1, $arg2] : [$arg2];
$classInstance = $r->newInstanceArgs($args);
my question is, why would the person do this? Doesn't this do the same?
$args = (is_subclass_of($className, 'ClassA')) ? [$arg1, $arg2] : [$arg2];
$classInstance = new $className($args);
The code is a few years old - the reason could have something to do with old PHP version features. I'm just looking for reasons and confirmation that the second way is "better". Thanks.
the answer is because of the "dynamic argument list." So the second version would have to look like this to be correct:
if (is_subclass_of($className, 'ClassA')) {
$classInstance = new $className($arg1, $arg2);
} else {
$classInstance = new $className($arg2);
}
passing an array to either constructor doesn't work:
class ClassA
{
public $arg1;
public $arg2;
public function __construct($arg1, $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
}
$className = 'ClassA';
$args = (is_subclass_of($className, 'ClassA')) ? [1, 2] : [2];
$classInstance = new $className($args);
var_dump($classInstance);
// object(ClassA)[1]
// public 'arg1' =>
// array (size=1)
// 0 => int 2
// public 'arg2' => null
Yes, for this purpose ReflectionClass is unnecessary.
You need to be sure that $r is not used in other part of the code before to remove it.
FYI:
is_subclass_of is available since PHP 4
ReflectionClass::isSubclassOf is available since PHP 5
You should check if instanceof match with your requirements, I think that it's a good solution
http://php.net/instanceof
($a instanceof MyClass)

Generating a php object, two levels deep

I'm new to php - objects and arrays, especially. Coming from a JavaScript world, I'm having a modicum of trouble understanding the right way to construct objects, that may easily be iterated.
I'd like to create an object (or array - although I suspect an object would be more suitable) with the following structure:
$client_body:
$cst:
$title: 'Unique string'
$copy: function_result()
$ser:
$title: 'Unique string'
$copy: function_result()
$imp
$title: 'Unique string'
$copy: function_result()
...
I've been trying with variations on the following, but with numerous errors:
$client_body = new stdClass();
$client_body->cst->title = 'Client case study';
$client_body->cst->copy = get_field('client_cst');
$client_body->ser->title = 'Our service';
$client_body->ser->copy = get_field('client_ser');
...
And it seems that, using this approach, I'd have to use a new stdClass invocation with each new top-level addition, which seems a little verbose.
Could someone point me in the right direction?
You can just typecast an array to an object:
$client_body = (object)array(
"cst" => (object)array(
"title" => "Unique string",
"copy" => function_result()
)
);
You can try this object class more OOP:
<?php
class ClientBody{
protected $cst;
protected $ser;
protected $imp;
public function __construct($cst = '', $ser ='', $imp = '')
{
$this->cst = $cst;
$this->ser = $ser;
$this->imp = $imp;
}
public function getCst()
{
return $this->cst;
}
public function getSer()
{
return $this->ser;
}
public function getImp()
{
return $this->imp;
}
public function setCst($value)
{
$this->cst = $value;
}
public function setSer($value)
{
$this->ser = $value;
}
public function setImp($value)
{
$this->imp = $value;
}
}
$myObject = new ClientBody('toto', 'titi', 'tata');
echo $myObject->getCst(); // output 'toto'
echo $myObject->getSer(); // output 'titi'
echo $myObject->getImp(); // output 'tata'
Or you could use json_decode($client_body, TRUE);

Laravel multiple object instantiation

I'm fairly new to Laravel and was wondering what the most efficient way of instantiating and making available multiple objects to my classes was.
An example of what I am doing currently would be, in kind of sudo code:
// MainController.php
<?php
Class MainController extends BaseController {
public function __construct() {
parent::construct();
}
// class code follows
}
// BaseContoller.php
<?php
use classFile;
Use repositoryFile;
use classFile2;
Use repositoryFile2;
..... and lets say 10 more "included" files
Class BaseController extends Controller {
var classFile;
var repositoryFile;
var classFile2;
var repositoryFile2;
..... and 10 more variables;
public function __construct() {
$this->classFile = new classFile;
$this->classFile = new classFile;
$this->repositoryFile = new repositoryFile;
$this->classFile2 = new classFile2;
$this->repositoryFile2 = new repositoryFile2;
..... and 10 more class instantiations
}
// class code follows
}
Hopefully that makes sense.....
Almost all of my classes that inherit BaseController will at some point make use of these objects so loading them all in for each class is I guess the right thing. My main two questions though are:
How expensive, from a pure code point of view, is instantiating multiple objects like this before they are needed. I have included them in the BaseController file because I found myself repeating these included definitions in the numerous files that inherit from BaseController.
From a Laravel point of view is there a better framework way of doing this kind of thing? Originally I had them being injected in through each classes constructor but again they were being repeated (the same definition in multiple files) and were becoming horribly large.
I've followed a lot of the Laracasts tuts as well as various reading material but I've not yet seen how people handle a large volume of objects like I'm trying to use. Or perhaps thats where I'm going "wrong"?
Cheers !
== Heres an example of the call for the homepage of the API I'm working on. It aggregates content from all across the site into a feed for a mobile app:
public function index()
{
$channels = $this->channelRepository->getChannels();
$allChannels = $this->channelRepository->getAllChannels();
$sponsors = $this->sponsorRepository->getSponsors();
$inactiveUserChannels = [];
// use the pattern maker, set the pattern we want to use
$this->patternMaker->setPattern(1);
$channelFeed = [];
if( userIsAuthenticated() )
{
$inactiveUserChannels = $this->userRepository->getUserInactiveChannels( 1 );
}
// Picks
$picks = $this->articleRepository->getArticles( 'picks', 25 );
$ads = $this->sponsorRepository->getWhereNotInCollection( $sponsors, 30 );
$response = $this->patternMaker->make( [ 'articles' => $picks, 'sponsors' => $ads ] );
$picks = $response->articles;
$ads = $response->sponsors;
// Whats on
$channel = 50;
$whatsOn = $this->articleRepository->getArticlesWithEvents(null); // get 20 articles from the whats on channel
$response = $this->patternMaker->make( [ 'articles' => $whatsOn, 'sponsors' => $ads ], "whats-on" );
$whatsOn = $response->articles;
$ads = $response->sponsors;
$channel = $this->channelTransformer->transform( getChannel($channels, $channel) );
$channel['articles'] = $whatsOn;
$channelFeed[] = $channel;
// create a new instance of the channel feed class and pass the required params to it
$this->channelFeed = $this->createChannelFeed( $allChannels, [ 48, 49, 51, 52 ], $ads, $inactiveUserChannels );
if( ! $response = cached("homepage") )
{
$data = [
'channels' => $this->channelTransformer->transformCollection( $channels )
,'adverts' => $this->sponsorTransformer->transformCollection( $sponsors->toArray() )
,'features' => $this->articleTransformer->transformCollection( $this->articleRepository->getArticles( 'featured', 25 ), [ 'showBody' => false] )
,'picks' => $picks
,'channelFeed' => $this->channelFeed->make()
];
cacheIt("homepage", $response, "1 hour");
}
return $this->respondFound(Lang::get('api.homepageFound'), $data);
}
This is early stage and I am refactoring as I go which is where this question of class dependencies has come from.
First, unless your constructor on the MainController have more logic you can just leave out the constructor all together and the BaseController constructor will be called directly.
You could do this:
Class BaseController extends Controller {
protected $classFile;
//repeat for all classes
function classFile() {
if(!$this->classFile) $this->clasFile = new classFile;
return $this->classFile;
}
//repeat for all classes
function useExample() {
$this->classFile()->randomMethod();
}
}
... this way atleast you dont instanciate more than needed.
That beeing said, it sounds like what you really want is Facades, and you could just go:
$channels = ChannelRepository::getChannels();
http://laravel.com/docs/facades

Use Reflection to find the class that a method belongs to

I'm working in Magento, but this is more of a general PHP question. The situation is that within Magento, there are classes that extend classes that extend classes that extend classes. I want to be able to quickly find which class actually contains the definition for a method and/or if that method is actually magic.
So for instance, if I'm 10 levels deep into classes extending others, and 4 of those 10 classes have a method called getHtml, I want to be able to find out which one of those methods is actually being called when I call $this->getHtml(). I would also like to be able to tell if getHtml is actually a magic method.
How can I do this with the PHP Reflection Class, or any other programmatic means?
(untested code below — if you find any bugs I'd appreciate an update in the comments)
The best you'll be able to do with the Reflection API is find the classes in the hierarchy where the method is not defined. The ReflectionClass's hasMethod feature will take parent classes into account — a better name for it might be aClassInTheHierarchyHasThisMethod. Consider this (quick top-my-head) inline function
$getClassesWithMethod = function($classOrObject, $method, $return=false) use(&$getClassesWithMethod)
{
$return = $return ? $return : new ArrayObject;
$r = new ReflectionClass($classOrObject);
if($r->hasMethod($method))
{
$return['has ' . $method . ' method'][] = $r->getName();
}
else
{
$return['no '. $method . ' method'][] = $r->getName();
}
$parent = $r->getParentClass();
if($parent)
{
$getClassesWithMethod($parent->getName(), $method, $return);
}
return $return;
};
$product = Mage::getModel('catalog/product');
$classesWithMethod = $getClassesWithMethod($product, 'load');
var_dump((array)$classesWithMethod);
Run the above, and you'll get
array (size=2)
'has load method' =>
array (size=4)
0 => string 'Mage_Catalog_Model_Product' (length=26)
1 => string 'Mage_Catalog_Model_Abstract' (length=27)
2 => string 'Mage_Core_Model_Abstract' (length=24)
'no load method' =>
array (size=1)
0 => string 'Varien_Object' (length=13)
So you know Varien_Object doesn't have the method load defined, which means it shows up first in Mage_Core_Model_Abstract. However, you won't know if there's also a definition in Mage_Catalog_Model_Abstract or Mage_Catalog_Model_Product. The Reflection API won't get you this.
What can get you this using the token_get_all method. This method can break a PHP file down into it's component PHP/Zend tokens. Once you have that, you can write a small parser in PHP that identifies method/function definitions in a specific class file. You can use this to recursively check the hierarchy. Again, an inline function.
$getClassesWithConcreteDefinition = function($classOrObject,$method,$return=false) use(&$getClassesWithConcreteDefinition)
{
$return = $return ? $return : new ArrayObject;
$r = new ReflectionClass($classOrObject);
$tokens = token_get_all(file_get_contents($r->getFilename()));
$is_function_context = false;
foreach($tokens as $token)
{
if(!is_array($token)){continue;}
$token['name'] = token_name($token[0]);
if($token['name'] == 'T_WHITESPACE'){ continue; }
if($token['name'] == 'T_FUNCTION')
{
$is_function_context = true;
continue;
}
if($is_function_context)
{
if($token[1] == $method)
{
$return[] = $r->getName();
}
$is_function_context = false;
continue;
}
}
$parent = $r->getParentClass();
if($parent)
{
$getClassesWithConcreteDefinition($parent->getName(),$method,$return);
}
return $return;
};
$product = Mage::getModel('catalog/product');
$hasActualDefinition = $getClassesWithConcreteDefinition($product, 'setData');
var_dump((array)$hasActualDefinition);
Here we're checking for the setData method. The above will return
array (size=2)
0 => string 'Mage_Catalog_Model_Abstract' (length=27)
1 => string 'Varien_Object' (length=13)
Because setData is defined in both the Mage_Catalog_Model_Abstract class and the Varien_Object class. You should be able to modify these functions to fit your own needs. Good luck!
4 of those 10 classes have a method called getHtml, I want to be able to find out which one of those methods is actually being called when I call $this->getHtml().
The method you're probably looking for is ReflectionClass::getMethods() which tells method-names and their resp. classname already.
If you can't find the concrete method-name, you need to look for __class.
The following is an example function that does this for public methods:
function traverseParentsForMethod($objOrClassname, $methodName) {
$refl = new ReflectionClass($objOrClassname);
$methods = $refl->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
if ($method->getName() === $methodName) {
return $method;
}
}
if ($methodName === '__call') {
return null;
}
return traverseParentsForMethod($objOrClassname, '__call');
}
Demo: https://eval.in/132292

PHP Object Validation

I'm currently working on an OO PHP application. I have a class called validation which I would like to use to check all of the data submitted is valid, however I obviously need somewhere to define the rules for each property to be checked. At the moment, I'm using arrays during the construction of a new object. eg:
$this->name = array(
'maxlength' => 10,
'minlength' => 2,
'required' => true,
'value' => $namefromparameter
)
One array for each property.
I would then call a static method from the validation class which would carry out various checks depending on the values defined in each array.
Is there a more efficient way of doing this?
Any advice appreciated.
Thanks.
I know the associative array is used commonly to configure things in PHP (it's called magic container pattern and is considered bad practice, btw), but why don't you create multiple validator classes instead, each of which able to handle one rule? Something like this:
interface IValidator {
public function validate($value);
}
$validators[] = new StringLengthValidator(2, 10);
$validators[] = new NotNollValidator();
$validators[] = new UsernameDoesNotExistValidator();
This has multiple advantages over the implementation using arrays:
You can document them (very important), phpdoc cannot parse comments for array keys.
Your code becomes typo-safe (array('reqiured' => true))
It is fully OO and does not introduce new concepts
It is more readable (although much more verbose)
The implementation of each constraint can be found intuitively (it's not in a 400-line function, but in the proper class)
EDIT: Here is a link to an answer I gave to a different question, but that is mostly applicable to this one as well.
Since using OO it would be cleaner if you used classes for validating properties. E.g.
class StringProperty
{
public $maxLength;
public $minlength;
public $required;
public $value;
function __construct($value,$maxLength,$minLength,$required)
{
$this->value = $value;
$this-> maxLength = $maxLength;
$this-> minLength = $minLength;
$this-> required = $required;
}
function isValidat()
{
// Check if it is valid
}
function getValidationErrorMessage()
{
}
}
$this->name = new StringProperty($namefromparameter,10,2,true);
if(!$this->name->isValid())
{
$validationMessage = $this->name-getValidationErrorMessage();
}
Using a class has the advantage of encapsulating logic inside of it that the array (basically a structure) does not have.
Maybe get inspired by Zend-Framework Validation.
So define a master:
class BaseValidator {
protected $msgs = array();
protected $params = array();
abstract function isValid($value);
public function __CONSTRUCT($_params) {
$this->params = $_params;
}
public function getMessages() {
// returns errors-messages
return $this->msgs;
}
}
And then build your custom validators:
class EmailValidator extends BaseValidator {
public function isValid($val=null) {
// if no value set use the params['value']
if ($val==null) {
$val = $this->params['value'];
}
// validate the value
if (strlen($val) < $this->params['maxlength']) {
$this->msgs[] = 'Length too short';
}
return count($this->msgs) > 0 ? false : true;
}
}
Finally your inital array could become something like:
$this->name = new EmailValidator(
array(
'maxlength' => 10,
'minlength' => 2,
'required' => true,
'value' => $namefromparameter,
),
),
);
validation could then be done like this:
if ($this->name->isValid()) {
echo 'everything fine';
} else {
echo 'Error: '.implode('<br/>', $this->name->getMessages());
}

Categories