Skip to content

Commit

Permalink
Automatically binding nested array iterators (#487)
Browse files Browse the repository at this point in the history
* build: upgrade dom requirement and loosen version range

* docs: update examples

* feature: trim whitespace when there are only template children
closes #363

* maintenance: phpstorm analysis improvements

* tweak: remove data-element attribute

* fix: recursive call to bindList if value is itself a list
for #486
  • Loading branch information
g105b authored Feb 29, 2024
1 parent ebe9545 commit 743c005
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/ListBinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public function bindListData(
// If the $listValue's first value is iterable, then treat this as a nested list.
if($this->isNested($listValue)) {
$elementBinder->bind(null, $listKey, $t);
$this->bindListData(
$listValue,
$t,
);
foreach($this->bindableCache->convertToKvp($listValue) as $key => $value) {
$elementBinder->bind($key, $value, $t);
}
Expand Down
34 changes: 34 additions & 0 deletions test/phpunit/DocumentBinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Gt\DomTemplate\Test\TestHelper\HTMLPageContent;
use Gt\DomTemplate\Test\TestHelper\ExampleClass;
use Gt\DomTemplate\Test\TestHelper\Model\Address;
use Gt\DomTemplate\Test\TestHelper\Model\ArrayIterator\Product\ProductList;
use Gt\DomTemplate\Test\TestHelper\Model\Country;
use Gt\DomTemplate\Test\TestHelper\Model\Customer;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -1366,6 +1367,39 @@ public function getIterator():Traversable {
self::assertCount(1, $ol->children);
}

public function testBindList_arrayIterator():void {
$document = new HTMLDocument(HTMLPageContent::HTML_SHOP_PRODUCTS);
$sut = new DocumentBinder($document);
$sut->setDependencies(...$this->documentBinderDependencies($document));

$categoryNameList = ["Category 1", "Category 2"];
$productNameList = [
["Product 1 in cat 1", "Product 2 in cat 1"],
["Product 3 in cat 2", "Product 4 in cat 2", "Product 5 in cat 2"],
];

$obj = new ProductList(
$categoryNameList,
$productNameList,
);
$sut->bindList($obj);

$categoryList = $document->querySelector("ul.categoryList");
self::assertCount(count($categoryNameList), $categoryList->children);

$productCount = 0;
foreach($categoryList->children as $categoryIndex => $categoryLi) {
self::assertSame("Category " . ($categoryIndex + 1), $categoryLi->querySelector("h2")->innerText);

self::assertCount(count($productNameList[$categoryIndex]), $categoryLi->querySelector("ul")->children);

foreach($categoryLi->querySelectorAll("ul li") as $productIndex => $productLi) {
self::assertSame("Product " . ($productCount + 1) . " in cat " . ($categoryIndex + 1), $productLi->textContent);
$productCount++;
}
}
}

private function documentBinderDependencies(HTMLDocument $document, mixed...$otherObjectList):array {
$htmlAttributeBinder = new HTMLAttributeBinder();
$htmlAttributeCollection = new HTMLAttributeCollection();
Expand Down
16 changes: 16 additions & 0 deletions test/phpunit/TestHelper/HTMLPageContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,22 @@ class HTMLPageContent {
</customer-list>
HTML;

const HTML_SHOP_PRODUCTS = <<<HTML
<!doctype html>
<h1>Categorised shop items</h1>
<ul class="categoryList">
<li data-list>
<h2 data-bind:text>Category name</h2>
<ul class="productList">
<li data-list data-bind:text="name">Product name</li>
</ul>
</li>
</ul>
HTML;


const HTML_REMOVE_UNBOUND = <<<HTML
<!doctype html>
<h1>Log in to the system</h1>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
namespace Gt\DomTemplate\Test\TestHelper\Model\ArrayIterator\Product;

class Product {
public function __construct(
public readonly string $name
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
namespace Gt\DomTemplate\Test\TestHelper\Model\ArrayIterator\Product;

use ArrayIterator;

class ProductList extends ArrayIterator {
/**
* @param array<string> $categoryNameList
* @param array<array<string>> $productNameList
*/
public function __construct(array $categoryNameList, array $productNameList) {
/** @var array<string, array<Product>> $categorisedProducts */
$categorisedProducts = [];

foreach($categoryNameList as $i => $categoryName) {
$categorisedProducts[$categoryName] = [];

foreach($productNameList[$i] as $productName) {
array_push($categorisedProducts[$categoryName], new Product($productName));
}
}

parent::__construct($categorisedProducts);
}
}

0 comments on commit 743c005

Please sign in to comment.