Skip to content

Commit

Permalink
Issue yiisoft#15845 Implement LooseGetSetInterface
Browse files Browse the repository at this point in the history
  • Loading branch information
mikehaertl committed Mar 8, 2018
1 parent fdd761d commit fa98f4e
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 4 deletions.
11 changes: 7 additions & 4 deletions framework/base/BaseObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,13 @@ public function __get($name)
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter();
}
if (method_exists($this, 'set' . $name)) {
} elseif (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
} elseif ($this instanceof LooseGetSetInterface) {
return $this->$name;
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}

throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}

/**
Expand All @@ -150,6 +151,8 @@ public function __set($name, $value)
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} elseif ($this instanceof LooseGetSetInterface) {
$this->$name = $value;
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
Expand Down
21 changes: 21 additions & 0 deletions framework/base/LooseGetSetInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/

namespace yii\base;

/**
* LooseGetSetInterface is an empty interface which can be attached to any
* class that extends from [[BaseObject]] to disable strict checks of existing
* properties. If a class implements this interface, object instances behave like
* PHP objects and allow to set and read-back non-existing properties. Note though,
* that PHP still throws an error if a property is read which was not set before.
*
* @since 2.1
*/
interface LooseGetSetInterface
{
}
205 changes: 205 additions & 0 deletions tests/framework/base/LooseGetSetInterfaceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/

namespace yiiunit\framework\base;

use yii\base\BaseObject;
use yii\base\LooseGetSetInterface;
use yiiunit\TestCase;

/**
* @group base
*/
class LooseGetSetInterfaceTest extends TestCase
{
/**
* @var NewObject
*/
protected $object;

protected function setUp()
{
parent::setUp();
$this->mockApplication();
$this->object = new NewLooseObject();
}

protected function tearDown()
{
parent::tearDown();
$this->object = null;
}

public function testCanSetNewProperty()
{
$this->assertFalse(isset($this->object->NewMember));
$this->object->NewMember = 'new value';
$this->assertTrue(isset($this->object->NewMember));
$this->assertSame('new value', $this->object->NewMember);
}

public function testUnsetNewProperty()
{
$this->object->NewMember = 'new value';
unset($this->object->NewMember);
$this->assertFalse(isset($this->object->NewMember));
$this->assertEmpty($this->object->NewMember);
}

public function testHasProperty()
{
$this->assertTrue($this->object->hasProperty('Text'));
$this->assertTrue($this->object->hasProperty('text'));
$this->assertFalse($this->object->hasProperty('Caption'));
$this->assertTrue($this->object->hasProperty('content'));
$this->assertFalse($this->object->hasProperty('content', false));
$this->assertFalse($this->object->hasProperty('Content'));
}

public function testCanGetProperty()
{
$this->assertTrue($this->object->canGetProperty('Text'));
$this->assertTrue($this->object->canGetProperty('text'));
$this->assertFalse($this->object->canGetProperty('Caption'));
$this->assertTrue($this->object->canGetProperty('content'));
$this->assertFalse($this->object->canGetProperty('content', false));
$this->assertFalse($this->object->canGetProperty('Content'));
}

public function testCanSetProperty()
{
$this->assertTrue($this->object->canSetProperty('Text'));
$this->assertTrue($this->object->canSetProperty('text'));
$this->assertFalse($this->object->canSetProperty('Object'));
$this->assertFalse($this->object->canSetProperty('Caption'));
$this->assertTrue($this->object->canSetProperty('content'));
$this->assertFalse($this->object->canSetProperty('content', false));
$this->assertFalse($this->object->canSetProperty('Content'));
}

public function testGetProperty()
{
$this->assertSame('default', $this->object->Text);
$this->expectException('yii\base\UnknownPropertyException');
$value2 = $this->object->Caption;
}

public function testSetProperty()
{
$value = 'new value';
$this->object->Text = $value;
$this->assertEquals($value, $this->object->Text);
}

public function testSetReadOnlyProperty()
{
$this->expectException('yii\base\InvalidCallException');
$this->object->object = 'test';
}

public function testIsset()
{
$this->assertTrue(isset($this->object->Text));
$this->assertNotEmpty($this->object->Text);

$this->object->Text = '';
$this->assertTrue(isset($this->object->Text));
$this->assertEmpty($this->object->Text);

$this->object->Text = null;
$this->assertFalse(isset($this->object->Text));
$this->assertEmpty($this->object->Text);

$this->assertFalse(isset($this->object->unknownProperty));
$isEmpty = empty($this->object->unknownProperty);
$this->assertTrue($isEmpty);
}

public function testUnset()
{
unset($this->object->Text);
$this->assertFalse(isset($this->object->Text));
$this->assertEmpty($this->object->Text);
}

public function testUnsetReadOnlyProperty()
{
$this->expectException('yii\base\InvalidCallException');
unset($this->object->object);
}

public function testArrayProperty()
{
$this->assertEquals([], $this->object->items);
// the following won't work
/*
$this->object->items[] = 1;
$this->assertEquals([1], $this->object->items);
*/
}

public function testObjectProperty()
{
$this->assertInstanceOf(NewObject::class, $this->object->object);
$this->assertEquals('object text', $this->object->object->text);
$this->object->object->text = 'new text';
$this->assertEquals('new text', $this->object->object->text);
}

public function testReadingWriteOnlyProperty()
{
$this->expectException('yii\base\InvalidCallException');
$this->expectExceptionMessage('Getting write-only property: yiiunit\framework\base\NewObject::writeOnly');
$this->object->writeOnly;
}
}


class NewLooseObject exteds BaseObject implements LooseGetSetInterface
{
private $_object = null;
private $_text = 'default';
private $_items = [];
public $content;

public function getText()
{
return $this->_text;
}

public function setText($value)
{
$this->_text = $value;
}

public function getObject()
{
if (!$this->_object) {
$this->_object = new self();
$this->_object->_text = 'object text';
}

return $this->_object;
}

public function getExecute()
{
return function ($param) {
return $param * 2;
};
}

public function getItems()
{
return $this->_items;
}

public function setWriteOnly()
{
}
}

0 comments on commit fa98f4e

Please sign in to comment.