here is my situation :
I have a class that is inherited by a dozen of others, in this class I have a copy method which returns a copy of itself.
I can use this method in the inheriting class but, obviously, the method always return an instance of the super class, not the one which inherit from it.
I would like my copy method to return an instance of the ihneriting class.
BaseEntity.php :
class BaseEntity
{
protected $id;
protected $name;
protected $active;
protected $deleted;
// ...
public function copy()
{
$copy = new BaseEntity();
$copy->id = $this->id;
$copy->name = $this->name;
$copy->active = $this->active;
$copy->deleted = $this->deleted;
return $copy;
}
}
User.php :
class User extends BaseEntity
{
// ...
// Properties are the same as BaseEntity, there is just more methods.
}
One more way to achieve what you want:
<?php
class BaseEntity
{
protected $id;
public function copy()
{
$classname = get_class($this);
$copy = new $classname;
return $copy;
}
}
class Test extends BaseEntity
{
}
$test = new Test;
$item = $test->copy();
var_dump($item); // object(Test)
I see two ways of doing this:
using clone - it will make a shallow copy of your object
using static for creating a new object
<?php
class BaseEntity {
public function copy() {
return new static;
}
}
class User extends BaseEntity {
}
$user = new User;
var_dump($user->copy());
Result of this code: https://3v4l.org/2naQI
Related
I have a basic class which I inject into another class
AClass
{
protected $thing;
public function setThing($thing)
{
$this->thing = $thing;
}
public function getThing()
{
return $this->thing;
}
}
This class is the SUT.
AnotherClass
{
protected $aClass;
protected $someOtherClass;
__construct(AClass $aClass, SomeOtherClass $someOtherClass)
{
$this->aClass = $aClass;
$this->someOtherClass = $someOtherClass;
}
public function thatImTesting()
{
...
$thing = "logic from {$this->someOtherClass} and some other stuff";
return $this->aClass->setThing($thing);
}
}
So I want to test AnotherClass so I mock SomeOtherClass and inject it into the SUT. However, I create a new AClass and inject it in because I don't want to mock the functions (as that would make no sense).
$someOtherClassMock = m::mock(SomeOtherClass::class, [
// mocking the functions here
]);
$aClass = new AClass();
$anotherClass = new AnotherClass($aClass, $someOtherClassMock);
$this->assertEquals('Something', $anotherClass->getThing());
As $anotherClass object is returned and I need to call a function to check the data in the test, is this still a unit test?
I have a parent class that depends on whether child class are instantiated.
class GoogleApp {
protected $auth_token;
public function __construct($scopes) {
$this->auth_token = $scopes;
}
}
class Gmail extends GoogleApp {
public function __construct() {
print_r($this->auth_token);
}
}
$googleApp = new GoogleApp('gmail'); // Change the actual class for all child instances
$gmail = new Gmail();
The idea is that all the children use the same auth_token (which is generated on whether the child classes are used - as of now, I'm just manually adding them to whether I included them in my code). Since I have quite a few child classes (like Calendar or Drive), do I have to inject the parent into each child instance or is there an easier way?
If I understand your request correctly, you're pretty close, you just need to declare your property as static.
class FooParent
{
protected static $scope = null;
public function __construct($scope)
{
self::$scope = $scope;
}
public function getScope()
{
return self::$scope;
}
}
class FooChild extends FooParent
{
public function __construct()
{
if (self::$scope === null) {
throw new Exception('Must set scope first.');
}
}
}
$parent = new FooParent('foo');
$child = new FooChild();
echo $child->getScope(), "\n"; // prints "foo"
I'm working in a project that works with OOP in PHP.
The problem is that when I try to instantiate two subclasses from an abstract class, only the first instance and not both.
DataBase.php:
abstract class DataBase {
private $_connection;
private static $_singleton = false;
/**
* Fetch an instance of the class.
*/
public final static function connect () {
if ( self::$_singleton === false ) {
self::$_singleton = new static();
}
return self::$_singleton;
}
}
UserDataBaseManager.php:
require_once 'DataBase.php';
class UserDataBase extends DataBase { (...) }
ImageDataBaseManager.php:
require_once 'DataBase.php';
class UserDataBase extends DataBase { (...) }
So, when I'm trying to instantiate ImageDataBase and UserDataBase:
$imageDB = ImageDataBaseManager::connect();
$userDB = UserDataBase::connect();
var_dump($userDB);
And this prints:
object(ImageDataBaseManager)#2 (1) { ["_connection":"DataBase":private]=> object(PDO)#3 (0) { } }
So I'm getting only the first class instance, but I want both.
how I can fix it?
When you initiate a new ImageDataBaseManager it stores the object in $_singleton of the abstract class and next time UserDataBase::connect request a new instance it returns it (static properties does not depends on instances). So it might not be a good idea to subclass a singleton pattern. However to get this working you need to store instance in the subclass not the parent class. Parent class and it's static properties are common to both (in runtime). Refer this code. The subclasses has their own $_singleton to store an instance.
abstract class DataBase {
private $_connection;
protected static $_singleton = false;
/**
* Fetch an instance of the class.
*/
public final static function connect () {
if ( static::$_singleton === false ) {
static::$_singleton = new static();
}
return static::$_singleton;
}
}
class UserDataBase extends DataBase { protected static $_singleton = false; }
class ImageDataBaseManager extends DataBase { protected static $_singleton = false; }
$imageDB = ImageDataBaseManager::connect();
$userDB = UserDataBase::connect();
var_dump($userDB);
Try this:
protected static $_singleton = false;
public final static function connect () {
if ( static::$_singleton === false ) {
static::$_singleton = new static();
}
I'm having strange problems when trying to persist a class of User that has a reference to many UserProperties. Note that a UserProperty will be managed by a cascade:persist.
UserProperties itself has a reference to a Property.
When creating a new User with a new UserProperty (which itself has a reference to an existing Property) it throws strange (strange as in i didn't expect it) error:
InvalidArgumentException: A new entity was found through the relationship 'UserProperty#property' that was not configured to cascade persist operations for entity
User:
class User extends IdentifiableObject {
// … other vars
/**
* #OneToMany(targetEntity="UserProperty", mappedBy="user", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $userProperties = null;
public function __construct() {
$this->userProperties = new ArrayCollection();
}
// … other methods
public function getUserProperties() {
return $this->userProperties;
}
public function setUserProperties($userProperties) {
$this->userProperties = $userProperties;
}
public function addUserProperty(UserProperty $userProperty) {
$userProperty->setUser($this);
$this->userProperties[] = $userProperty;
}
}
UserProperty:
class UserProperty extends IdentifiableObject {
/**
* #OneToOne(targetEntity="Property")
* #JoinColumn(name="propertyID")
*/
private $property;
public function getProperty() {
return $this->property;
}
public function setProperty($property) {
$this->property = $property;
}
}
Property class has no references to either class.
And finally my testClass using PHPUnit:
class UserDaoTest extends PHPUnit_Framework_TestCase {
private static $userDao;
private static $propertyDao;
public static function setUpBeforeClass() {
//this will make the EntityManager called inside our DAOImpl point to our test database...
define('__DBNAME__', 'db_test');
createCleanTestDatabase();
self::$userDao = new UserDaoImpl();
self::$propertyDao = new PropertyDaoImpl();
}
public function testEntityClassVariable() {
$this->assertEquals("User", self::$userDao->getEntityClass());
}
public function testPersistUserWithoutProperties() {
$user = new User();
$user->setUserName("tester1");
$user->setUserType(1);
self::$userDao->persist($user);
self::$userDao->flush();
$this->assertEquals(1, count(self::$userDao->findAll()));
}
public function testPersistUserWithProperties() {
$user = new User();
$user->setUserName("tester2");
$user->setUserType(1);
$property = new Property();
$property->setName("propertyName");
$property->setType(1);
self::$propertyDao->persist($property);
self::$propertyDao->flush();
$userProperty = new UserProperty();
$userProperty->setProperty($property);
$userProperty->setValue("test");
$user->addUserProperty($userProperty);
self::$userDao->persist($user);
self::$userDao->flush();
$this->assertEquals(2, count(self::$userDao->findAll()));
$userInDB = self::$userDao->find($user);
$this->assertNotNull($userInDB);
$this->assertEquals(1, count($userInDB->getUserProperties()));
}
}
The strange thing is that the Property is indeed created in the Database.
Also the test works perfectly fine IF i use the userDao->persist to save the Property (instead of the propertyDao...
Any help would be appreciated, thanks in advance!
The problem was that i was using a different entityManager in each dao so effectively having a different UnitOfWork for each DAO. When i made the entity a singleton so that each DAO had the same reference to it.
I am writing some tests for a Magento module, using Ivan Chepurnyi's extension, and I'm having trouble using the mock objects.
Here is the class:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
public function __construct()
{
$this->_salesCollection = Mage::getModel('module/classA')->getCollection()
->addFieldToFilter('id', $this->_getId());
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_salesCollection->count();
}
}
The method I'm trying to test is getSalesTotalNumber().
And here is the test:
<?php
class Namespace_Module_Test_Block_Class extends EcomDev_PHPUnit_Test_Case
{
private $_mock;
public function setUp()
{
$this->_mock = $this->getMock('Namespace_Module_Block_Class',
array('_getId')
);
$this->_mock->expects($this->any())
->method('_getId')
->will($this->returnValue(1024));
parent::setUp();
}
/**
* #test
* #loadFixture
* #loadExpectation
*/
public function testSalesTotalNumber()
{
$actual = $this->_mock->getSalesTotalValue();
$expected = $this->_getExpectations()->getSalesTotalNumber();
$this->assertEquals($expected, $actual);
}
}
As you can see, what I want to do is overwrite the _getId() method so that it returns an id which match the id in the fixture and so load the collection. But it doesn't work :-(.
In my test, if I echo $this->_mock->_getId() it returns the correct Id (1024). But in the __construct() of my class $this->_getId() returns null, which is the expected value during testing (I mean, during testing there is no session, so it can't get the object's Id as I store it in a session variable). So the _getId() method isn't mocked by my test case.
Any help will be highly appreciated.
So my problem was not in the mock/test but in the class.
I have moved the content of __construct() into a protected method which returns the collection object. That's how my class looks like now:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
protected function _getAffiliateSales()
{
if (is_null($this->_salesCollection)) {
$affiliateId = $this->_getId();
$this->_salesCollection = Mage::getModel('module/classA')
->addFieldToFilter('id', $affiliateId);
}
return $this->_salesCollection;
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_getAffiliateSales()->count();
}
}