Skip to content

Commit

Permalink
Implemented nullable association using empty
Browse files Browse the repository at this point in the history
  • Loading branch information
stekycz committed Mar 2, 2017
1 parent c5b56dd commit 330005d
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 16 deletions.
21 changes: 13 additions & 8 deletions src/Schematic/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Entry
const INDEX_ENTRYCLASS = 0;
const INDEX_MULTIPLICITY = 1;
const INDEX_EMBEDDING = 2;
const INDEX_NULLABLE = 3;

/**
* @var array
Expand Down Expand Up @@ -64,18 +65,19 @@ private static function parseAssociations($class)

foreach (static::$associations as $association => $entryClass) {
$matches = [];
$result = preg_match('#^([^.[\]]+)(\.[^.[\]]*)?(\[\])?$#', $association, $matches);
$result = preg_match('#^(\?)?([^.[\]]+)(\.[^.[\]]*)?(\[\])?$#', $association, $matches);

if ($result === 0 || (!empty($matches[2]) && !empty($matches[3]))) {
if ($result === 0 || (!empty($matches[3]) && !empty($matches[4]))) {
throw new InvalidArgumentException('Invalid association definition given: ' . $association);
}

self::$parsedAssociations[$class][$matches[1]] = [
self::$parsedAssociations[$class][$matches[2]] = [
self::INDEX_ENTRYCLASS => $entryClass,
self::INDEX_MULTIPLICITY => !empty($matches[3]),
self::INDEX_EMBEDDING => !empty($matches[2]) ?
($matches[2] === '.' ? $matches[1] . '_' : substr($matches[2], 1)) :
self::INDEX_MULTIPLICITY => !empty($matches[4]),
self::INDEX_EMBEDDING => !empty($matches[3]) ?
($matches[3] === '.' ? $matches[2] . '_' : substr($matches[3], 1)) :
FALSE,
self::INDEX_NULLABLE => !empty($matches[1]),
];
}
}
Expand All @@ -101,15 +103,18 @@ public function __get($name)
$this->readEmbeddedEntry($association[self::INDEX_EMBEDDING]) :
$this->readData($name);

if ($data === NULL) {
if (!$association[self::INDEX_MULTIPLICITY] && (
$data === NULL
|| ($association[self::INDEX_NULLABLE] && empty($data))
)) {
return $this->data[$name] = NULL;
}

$entryClass = $association[self::INDEX_ENTRYCLASS];
$entriesClass = $this->entriesClass;

return $this->data[$name] = $association[self::INDEX_MULTIPLICITY] ?
new $entriesClass($data, $entryClass) :
new $entriesClass((array) $data, $entryClass) :
new $entryClass($data, $this->entriesClass);
}

Expand Down
92 changes: 88 additions & 4 deletions tests/SchematicTests/EntryTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,35 @@ class EntryTest extends TestCase
Assert::same(100, $order->customer->id);
}

/**
* @dataProvider provideDataNullableRelation
*/
public function testEntriesAccessToNullableParameter($customer)
{
$order = new Order([
'customer' => $customer,
'orderItems' => [],
]);
Assert::null($order->customer);
}


public function testEntriesClass()
public function provideDataNullableRelation()
{
return [
[[]],
[false],
[null],
[0],
[0.0],
[''],
];
}

/**
* @dataProvider provideDataNullableCollection
*/
public function testEntriesClass($lastCollectionValue)
{
$order = new Order([
'orderItems' => [
Expand All @@ -71,6 +98,10 @@ class EntryTest extends TestCase
'id' => 2,
'tags' => [],
],
[
'id' => 3,
'tags' => $lastCollectionValue,
],
],
], CustomEntries::class);

Expand All @@ -79,18 +110,37 @@ class EntryTest extends TestCase
$orderItems = $order->orderItems->toArray();
/** @var OrderItem $firstOrderItem */
$firstOrderItem = reset($orderItems);
/** @var OrderItem $lastOrderItem */
$lastOrderItem = end($orderItems);

Assert::type(CustomEntries::class, $firstOrderItem->tags);
Assert::type(CustomEntries::class, $lastOrderItem->tags);
}


public function testEmbeddedEntries()
public function provideDataNullableCollection()
{
return [
[[]],
[false],
[null],
[0],
[0.0],
[''],
];
}

/**
* @dataProvider provideDataNullableCustomer
*/
public function testEmbeddedEntries($customerId, $customerName)
{
$book = new Book([
'id' => 12,
'title' => 'PHP: The Bad Parts',
'tag_name' => 'bestseller',
'customer_id' => 20,
'customer_id' => $customerId,
'customer_name' => $customerName,
'a_firstname' => 'John',
'a_surname' => 'Doe',
]);
Expand All @@ -99,7 +149,41 @@ class EntryTest extends TestCase
Assert::same('bestseller', $book->tag->name);

Assert::type(Customer::class, $book->customer);
Assert::same(20, $book->customer->id);
Assert::same($customerId, $book->customer->id);
Assert::same($customerName, $book->customer->name);

Assert::type(Author::class, $book->author);
Assert::same('John', $book->author->firstname);
Assert::same('Doe', $book->author->surname);
}


public function provideDataNullableCustomer()
{
return [
[20, 'Jack'],
[null, 'Jack'],
[20, null],
];
}


public function testNullableEmbeddedEntries()
{
$book = new Book([
'id' => 12,
'title' => 'PHP: The Bad Parts',
'tag_name' => 'bestseller',
'customer_id' => null,
'customer_name' => null,
'a_firstname' => 'John',
'a_surname' => 'Doe',
]);

Assert::type(Tag::class, $book->tag);
Assert::same('bestseller', $book->tag->name);

Assert::null($book->customer);

Assert::type(Author::class, $book->author);
Assert::same('John', $book->author->firstname);
Expand Down
10 changes: 6 additions & 4 deletions tests/SchematicTests/entries.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Order extends Identified
{

protected static $associations = [
'customer' => Customer::class,
'?customer' => Customer::class,
'orderItems[]' => OrderItem::class,
];

Expand All @@ -40,12 +40,14 @@ class OrderItem extends Identified
{

protected static $associations = [
'tags[]' => Tag::class,
'?tags[]' => Tag::class,
];

}


/**
* @property-read string|null $name
*/
class Customer extends Identified
{

Expand Down Expand Up @@ -88,7 +90,7 @@ class Book extends Identified

protected static $associations = [
'tag.' => Tag::class,
'customer.' => Customer::class,
'?customer.' => Customer::class,
'author.a_' => Author::class,
];

Expand Down

0 comments on commit 330005d

Please sign in to comment.