Skip to content

Commit

Permalink
zendframework#186 FeatureSet to handle more than one feature of a type
Browse files Browse the repository at this point in the history
  • Loading branch information
alextech committed Nov 9, 2016
1 parent ae46299 commit 60585df
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 21 deletions.
38 changes: 24 additions & 14 deletions src/TableGateway/Feature/FeatureSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class FeatureSet
protected $tableGateway = null;

/**
* @var AbstractFeature[]
* @var string[]AbstractFeature[]
*/
protected $features = [];

Expand All @@ -46,14 +46,14 @@ public function setTableGateway(AbstractTableGateway $tableGateway)

public function getFeatureByClassName($featureClassName)
{
$feature = false;
foreach ($this->features as $potentialFeature) {
if ($potentialFeature instanceof $featureClassName) {
$feature = $potentialFeature;
break;
}
if(!array_key_exists($featureClassName, $this->features)) return false;

$featuresByType = $this->features[$featureClassName];
if(count($featuresByType) == 1) {
return $featuresByType[0];
} else {
return $featuresByType;
}
return $feature;
}

public function addFeatures(array $features)
Expand All @@ -69,7 +69,7 @@ public function addFeature(AbstractFeature $feature)
if ($this->tableGateway instanceof TableGatewayInterface) {
$feature->setTableGateway($this->tableGateway);
}
$this->features[] = $feature;
$this->features[get_class($feature)][] = $feature;
return $this;
}

Expand Down Expand Up @@ -132,8 +132,8 @@ public function callMagicSet($property, $value)
public function canCallMagicCall($method)
{
if (!empty($this->features)) {
foreach ($this->features as $feature) {
if (method_exists($feature, $method)) {
foreach ($this->features as $featureClass => $featuresSet) {
if (method_exists($featureClass, $method)) {
return true;
}
}
Expand All @@ -149,9 +149,19 @@ public function canCallMagicCall($method)
*/
public function callMagicCall($method, $arguments)
{
foreach ($this->features as $feature) {
if (method_exists($feature, $method)) {
return $feature->$method($arguments);
foreach ($this->features as $featureClass => $featuresSet) {
if (method_exists($featureClass, $method)) {

// iterator management instead of foreach to avoid extra conditions and indentations
reset($featuresSet);
$featureReturn = null;
while($featureReturn === null) {
$current = current($featuresSet);
$featureReturn = $current->$method($arguments);
next($featuresSet);
}

return $featureReturn;
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/TableGateway/Feature/SequenceFeature.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ public function nextSequenceId()
* Return the most recent value from the specified sequence in the database.
* @return int
*/
public function lastSequenceId()
public function lastSequenceId($sequenceName = null)
{
if($sequenceName !== null && strcmp($sequenceName, $this->sequenceName) !== 0) return null;

$platform = $this->tableGateway->adapter->getPlatform();
$platformName = $platform->getName();

Expand Down
81 changes: 75 additions & 6 deletions test/TableGateway/Feature/FeatureSetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace ZendTest\Db\TableGateway\Feature;

use ReflectionClass;
use Zend\Db\TableGateway\Feature\AbstractFeature;
use Zend\Db\TableGateway\Feature\FeatureSet;
use Zend\Db\TableGateway\Feature\MasterSlaveFeature;
use Zend\Db\TableGateway\Feature\SequenceFeature;
Expand Down Expand Up @@ -80,6 +81,55 @@ public function testAddFeatureThatFeatureHasTableGatewayButFeatureSetDoesNotHave
$this->assertInstanceOf('Zend\Db\TableGateway\Feature\FeatureSet', $featureSet->addFeature($feature));
}

/**
* @covers Zend\Db\TableGateway\Feature\FeatureSet::getFeatureByClassName
*/
public function testGetSingleFeatureByClassName() {
$featureMock = $this->getMock(AbstractFeature::class);

$featureSet = new FeatureSet();
$featureSet->addFeature($featureMock);

$this->assertInstanceOf(
get_class($featureMock),
$featureSet->getFeatureByClassName(get_class($featureMock)),
"When only one feature of its type is added to FeatureSet, getFeatureByClassName() should return that single instance"
);
}

/**
* @covers Zend\Db\TableGateway\Feature\FeatureSet::getFeatureByClassName
*/
public function testGetAllFeaturesOfSameTypeByClassName() {
$featureMock1 = $this->getMock(AbstractFeature::class);
$featureMock2 = $this->getMock(AbstractFeature::class);

$featureSet = new FeatureSet();
$featureSet->addFeature($featureMock1);
$featureSet->addFeature($featureMock2);

$features = $featureSet->getFeatureByClassName(get_class($featureMock1));

$this->assertTrue(is_array($features), "When multiple features of same type are added, they all should be return in array");

$this->assertInstanceOf(get_class($featureMock1), $features[0]);
$this->assertInstanceOf(get_class($featureMock2), $features[1]);
}

/**
* @covers Zend\Db\TableGateway\Feature\FeatureSet::getFeatureByClassName
*/
public function testGetFeatureByClassNameReturnsFalseIfNotAdded() {
$featureMock = $this->getMock(AbstractFeature::class);

$featureSet = new FeatureSet();

$this->assertFalse(
$featureSet->getFeatureByClassName(get_class($featureMock)),
"Requesting unregistered feature should return false"
);
}

/**
* @covers Zend\Db\TableGateway\Feature\FeatureSet::canCallMagicCall
*/
Expand Down Expand Up @@ -126,16 +176,36 @@ public function testCanCallMagicCallReturnsFalseWhenNoFeaturesHaveBeenAdded()
*/
public function testCallMagicCallSucceedsForValidMethodOfAddedFeature()
{
$sequenceName = 'table_sequence';
$featureSet = new FeatureSet;
$featureSet->addFeature($this->getMockSequence('table_sequence', 1));
$this->assertEquals(1, $featureSet->callMagicCall('lastSequenceId', null));
}

/**
* @covers Zend\Db\TableGateway\Feature\FeatureSet::callMagicCall
*/
public function testCallMagicMethodAllSimilarFeaturesUntilNotNull() {
$featureSet = new FeatureSet();

$featureSet->addFeature($this->getMockSequence('seq_1', 1));
$featureSet->addFeature($this->getMockSequence('seq_2', 2));
$featureSet->addFeature($this->getMockSequence('seq_3', 3));

$result = $featureSet->callMagicCall('lastSequenceId','seq_2');

$this->assertEquals(2, $result);
}

// FeatureSet uses method_exists which does not work on mock objects. Therefore, need a real object.
private function getMockSequence($sequenceName, $expectedCurrVal) {
$platformMock = $this->getMock('Zend\Db\Adapter\Platform\Postgresql');
$platformMock->expects($this->any())
->method('getName')->will($this->returnValue('PostgreSQL'));

$resultMock = $this->getMock('Zend\Db\Adapter\Driver\Pgsql\Result');
$resultMock->expects($this->any())
->method('current')
->will($this->returnValue(['currval' => 1]));
->will($this->returnValue(['currval' => $expectedCurrVal]));

$statementMock = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$statementMock->expects($this->any())
Expand All @@ -162,10 +232,9 @@ public function testCallMagicCallSucceedsForValidMethodOfAddedFeature()
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($tableGatewayMock, $adapterMock);

$feature = new SequenceFeature('id', 'table_sequence');
$feature = new SequenceFeature('id', $sequenceName);
$feature->setTableGateway($tableGatewayMock);
$featureSet = new FeatureSet;
$featureSet->addFeature($feature);
$this->assertEquals(1, $featureSet->callMagicCall('lastSequenceId', null));

return $feature;
}
}

0 comments on commit 60585df

Please sign in to comment.