Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API rescue master-branch PR: Use Generators for ORM #10450

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/Forms/GridField/GridFieldExportButton.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,6 @@ public function generateExportFileData($gridField)

// Remove limit as the list may be paginated, we want the full list for the export
$items = $items->limit(null);
// Use Generator in applicable cases to reduce memory consumption
$items = $items instanceof DataList
? $items->getGenerator()
: $items;

/** @var DataObject $item */
foreach ($items as $item) {
Expand Down
23 changes: 10 additions & 13 deletions src/ORM/ArrayList.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace SilverStripe\ORM;

use ArrayIterator;
use InvalidArgumentException;
use Iterator;
use LogicException;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\Deprecation;
Expand Down Expand Up @@ -103,19 +103,16 @@ public function exists()
/**
* Returns an Iterator for this ArrayList.
* This function allows you to use ArrayList in foreach loops
*
* @return ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$items = array_map(
function ($item) {
return is_array($item) ? new ArrayData($item) : $item;
},
$this->items ?? []
);
return new ArrayIterator($items);
public function getIterator(): Iterator
{
foreach ($this->items as $i => $item) {
if (is_array($item)) {
yield new ArrayData($item);
} else {
yield $item;
}
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/ORM/Connect/DBSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ public function requireTable(
if ($dbID && isset($options[$dbID])) {
if (preg_match('/ENGINE=([^\s]*)/', $options[$dbID] ?? '', $alteredEngineMatches)) {
$alteredEngine = $alteredEngineMatches[1];
$tableStatus = $this->query(sprintf('SHOW TABLE STATUS LIKE \'%s\'', $table))->first();
$tableStatus = $this->query(sprintf('SHOW TABLE STATUS LIKE \'%s\'', $table))->record();
$tableOptionsChanged = ($tableStatus['Engine'] != $alteredEngine);
}
}
Expand Down
35 changes: 7 additions & 28 deletions src/ORM/Connect/MySQLQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace SilverStripe\ORM\Connect;

use Iterator;

/**
* A result-set from a MySQL database (using MySQLiConnector)
* Note that this class is only used for the results of non-prepared statements
Expand Down Expand Up @@ -45,44 +47,21 @@ public function __destruct()
}
}

public function seek($row)
public function getIterator(): Iterator
{
if (is_object($this->handle)) {
// Fix for https://github.com/silverstripe/silverstripe-framework/issues/9097 without breaking the seek() API
$this->handle->data_seek($row);
$result = $this->nextRecord();
$this->handle->data_seek($row);
return $result;
while ($data = $this->handle->fetch_assoc()) {
yield $data;
}
}
return null;
}

public function numRecords()
{
if (is_object($this->handle)) {
return $this->handle->num_rows;
}
return null;
}

public function nextRecord()
{
$floatTypes = [MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_NEWDECIMAL];

if (is_object($this->handle) && ($row = $this->handle->fetch_array(MYSQLI_NUM))) {
$data = [];
foreach ($row as $i => $value) {
if (!isset($this->columns[$i])) {
throw new DatabaseException("Can't get metadata for column $i");
}
if (in_array($this->columns[$i]->type, $floatTypes ?? [])) {
$value = (float)$value;
}
$data[$this->columns[$i]->name] = $value;
}
return $data;
} else {
return false;
}
return null;
}
}
77 changes: 30 additions & 47 deletions src/ORM/Connect/MySQLStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace SilverStripe\ORM\Connect;

use Iterator;
use mysqli_result;
use mysqli_stmt;

Expand Down Expand Up @@ -56,6 +57,26 @@ class MySQLStatement extends Query
*/
protected $boundValues = [];

/**
* Hook the result-set given into a Query class, suitable for use by SilverStripe.
* @param mysqli_stmt $statement The related statement, if present
* @param mysqli_result $metadata The metadata for this statement
*/
public function __construct($statement, $metadata)
{
$this->statement = $statement;
$this->metadata = $metadata;

// Immediately bind and buffer
$this->bind();
}

public function __destruct()
{
$this->statement->close();
$this->currentRecord = false;
}

/**
* Binds this statement to the variables
*/
Expand All @@ -82,58 +103,20 @@ protected function bind()
call_user_func_array([$this->statement, 'bind_result'], $variables ?? []);
}

/**
* Hook the result-set given into a Query class, suitable for use by SilverStripe.
* @param mysqli_stmt $statement The related statement, if present
* @param mysqli_result $metadata The metadata for this statement
*/
public function __construct($statement, $metadata)
{
$this->statement = $statement;
$this->metadata = $metadata;

// Immediately bind and buffer
$this->bind();
}

public function __destruct()
public function getIterator(): Iterator
{
$this->statement->close();
$this->currentRecord = false;
}

public function seek($row)
{
$this->rowNum = $row - 1;

// Fix for https://github.com/silverstripe/silverstripe-framework/issues/9097 without breaking the seek() API
$this->statement->data_seek($row);
$result = $this->next();
$this->statement->data_seek($row);
return $result;
while ($this->statement->fetch()) {
// Dereferenced row
$row = [];
foreach ($this->boundValues as $key => $value) {
$row[$key] = $value;
}
yield $row;
}
}

public function numRecords()
{
return $this->statement->num_rows();
}

public function nextRecord()
{
// Skip data if out of data
if (!$this->statement->fetch()) {
return false;
}

// Dereferenced row
$row = [];
foreach ($this->boundValues as $key => $value) {
$floatTypes = [MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_NEWDECIMAL];
if (in_array($this->types[$key], $floatTypes ?? [])) {
$value = (float)$value;
}
$row[$key] = $value;
}
return $row;
}
}
23 changes: 7 additions & 16 deletions src/ORM/Connect/PDOQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace SilverStripe\ORM\Connect;

use ArrayIterator;
use Iterator;

/**
* A result-set from a PDO database.
*/
Expand All @@ -14,7 +17,7 @@ class PDOQuery extends Query

/**
* Hook the result-set given into a Query class, suitable for use by SilverStripe.
* @param PDOStatement $statement The internal PDOStatement containing the results
* @param PDOStatementHandle $statement The internal PDOStatement containing the results
*/
public function __construct(PDOStatementHandle $statement)
{
Expand All @@ -26,25 +29,13 @@ public function __construct(PDOStatementHandle $statement)
$statement->closeCursor();
}

public function seek($row)
public function getIterator(): Iterator
{
$this->rowNum = $row - 1;
return $this->nextRecord();
return new ArrayIterator($this->results);
}

public function numRecords()
{
return count($this->results ?? []);
}

public function nextRecord()
{
$index = $this->rowNum + 1;

if (isset($this->results[$index])) {
return $this->results[$index];
} else {
return false;
}
return count($this->results);
}
}
Loading