Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/storage/lisk/LiskDAO.php
Show First 20 Lines • Show All 187 Lines • ▼ Show 20 Lines | abstract class LiskDAO extends Phobject | ||||
private static $processIsolationLevel = 0; | private static $processIsolationLevel = 0; | ||||
private static $transactionIsolationLevel = 0; | private static $transactionIsolationLevel = 0; | ||||
private $ephemeral = false; | private $ephemeral = false; | ||||
private $forcedConnection; | private $forcedConnection; | ||||
private static $connections = array(); | private static $connections = array(); | ||||
private $inSet = null; | |||||
protected $id; | protected $id; | ||||
protected $phid; | protected $phid; | ||||
protected $dateCreated; | protected $dateCreated; | ||||
protected $dateModified; | protected $dateModified; | ||||
/** | /** | ||||
* Build an empty object. | * Build an empty object. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | public function loadAllFromArray(array $rows) { | ||||
foreach ($rows as $row) { | foreach ($rows as $row) { | ||||
$obj = clone $this; | $obj = clone $this; | ||||
if ($id_key && isset($row[$id_key])) { | if ($id_key && isset($row[$id_key])) { | ||||
$result[$row[$id_key]] = $obj->loadFromArray($row); | $result[$row[$id_key]] = $obj->loadFromArray($row); | ||||
} else { | } else { | ||||
$result[] = $obj->loadFromArray($row); | $result[] = $obj->loadFromArray($row); | ||||
} | } | ||||
if ($this->inSet) { | |||||
$this->inSet->addToSet($obj); | |||||
} | |||||
} | } | ||||
return $result; | return $result; | ||||
} | } | ||||
/** | |||||
* This method helps to prevent the 1+N queries problem. It happens when you | |||||
* execute a query for each row in a result set. Like in this code: | |||||
* | |||||
* COUNTEREXAMPLE, name=Easy to write but expensive to execute | |||||
* $diffs = id(new DifferentialDiff())->loadAllWhere( | |||||
* 'revisionID = %d', | |||||
* $revision->getID()); | |||||
* foreach ($diffs as $diff) { | |||||
* $changesets = id(new DifferentialChangeset())->loadAllWhere( | |||||
* 'diffID = %d', | |||||
* $diff->getID()); | |||||
* // Do something with $changesets. | |||||
* } | |||||
* | |||||
* One can solve this problem by reading all the dependent objects at once and | |||||
* assigning them later: | |||||
* | |||||
* COUNTEREXAMPLE, name=Cheaper to execute but harder to write and maintain | |||||
* $diffs = id(new DifferentialDiff())->loadAllWhere( | |||||
* 'revisionID = %d', | |||||
* $revision->getID()); | |||||
* $all_changesets = id(new DifferentialChangeset())->loadAllWhere( | |||||
* 'diffID IN (%Ld)', | |||||
* mpull($diffs, 'getID')); | |||||
* $all_changesets = mgroup($all_changesets, 'getDiffID'); | |||||
* foreach ($diffs as $diff) { | |||||
* $changesets = idx($all_changesets, $diff->getID(), array()); | |||||
* // Do something with $changesets. | |||||
* } | |||||
* | |||||
* The method @{method:loadRelatives} abstracts this approach which allows | |||||
* writing a code which is simple and efficient at the same time: | |||||
* | |||||
* name=Easy to write and cheap to execute | |||||
* $diffs = $revision->loadRelatives(new DifferentialDiff(), 'revisionID'); | |||||
* foreach ($diffs as $diff) { | |||||
* $changesets = $diff->loadRelatives( | |||||
* new DifferentialChangeset(), | |||||
* 'diffID'); | |||||
* // Do something with $changesets. | |||||
* } | |||||
* | |||||
* This will load dependent objects for all diffs in the first call of | |||||
* @{method:loadRelatives} and use this result for all following calls. | |||||
* | |||||
* The method supports working with set of sets, like in this code: | |||||
* | |||||
* $diffs = $revision->loadRelatives(new DifferentialDiff(), 'revisionID'); | |||||
* foreach ($diffs as $diff) { | |||||
* $changesets = $diff->loadRelatives( | |||||
* new DifferentialChangeset(), | |||||
* 'diffID'); | |||||
* foreach ($changesets as $changeset) { | |||||
* $hunks = $changeset->loadRelatives( | |||||
* new DifferentialHunk(), | |||||
* 'changesetID'); | |||||
* // Do something with hunks. | |||||
* } | |||||
* } | |||||
* | |||||
* This code will execute just three queries - one to load all diffs, one to | |||||
* load all their related changesets and one to load all their related hunks. | |||||
* You can try to write an equivalent code without using this method as | |||||
* a homework. | |||||
* | |||||
* The method also supports retrieving referenced objects, for example authors | |||||
* of all diffs (using shortcut @{method:loadOneRelative}): | |||||
* | |||||
* foreach ($diffs as $diff) { | |||||
* $author = $diff->loadOneRelative( | |||||
* new PhabricatorUser(), | |||||
* 'phid', | |||||
* 'getAuthorPHID'); | |||||
* // Do something with author. | |||||
* } | |||||
* | |||||
* It is also possible to specify additional conditions for the `WHERE` | |||||
* clause. Similarly to @{method:loadAllWhere}, you can specify everything | |||||
* after `WHERE` (except `LIMIT`). Contrary to @{method:loadAllWhere}, it is | |||||
* allowed to pass only a constant string (`%` doesn't have a special | |||||
* meaning). This is intentional to avoid mistakes with using data from one | |||||
* row in retrieving other rows. Example of a correct usage: | |||||
* | |||||
* $status = $author->loadOneRelative( | |||||
* new PhabricatorCalendarEvent(), | |||||
* 'userPHID', | |||||
* 'getPHID', | |||||
* '(UNIX_TIMESTAMP() BETWEEN dateFrom AND dateTo)'); | |||||
* | |||||
* @param LiskDAO Type of objects to load. | |||||
* @param string Name of the column in target table. | |||||
* @param string Method name in this table. | |||||
* @param string Additional constraints on returned rows. It supports no | |||||
* placeholders and requires putting the WHERE part into | |||||
* parentheses. It's not possible to use LIMIT. | |||||
* @return list Objects of type $object. | |||||
* | |||||
* @task load | |||||
*/ | |||||
public function loadRelatives( | |||||
LiskDAO $object, | |||||
$foreign_column, | |||||
$key_method = 'getID', | |||||
$where = '') { | |||||
if (!$this->inSet) { | |||||
id(new LiskDAOSet())->addToSet($this); | |||||
} | |||||
$relatives = $this->inSet->loadRelatives( | |||||
$object, | |||||
$foreign_column, | |||||
$key_method, | |||||
$where); | |||||
return idx($relatives, $this->$key_method(), array()); | |||||
} | |||||
/** | |||||
* Load referenced row. See @{method:loadRelatives} for details. | |||||
* | |||||
* @param LiskDAO Type of objects to load. | |||||
* @param string Name of the column in target table. | |||||
* @param string Method name in this table. | |||||
* @param string Additional constraints on returned rows. It supports no | |||||
* placeholders and requires putting the WHERE part into | |||||
* parentheses. It's not possible to use LIMIT. | |||||
* @return LiskDAO Object of type $object or null if there's no such object. | |||||
* | |||||
* @task load | |||||
*/ | |||||
final public function loadOneRelative( | |||||
LiskDAO $object, | |||||
$foreign_column, | |||||
$key_method = 'getID', | |||||
$where = '') { | |||||
$relatives = $this->loadRelatives( | |||||
$object, | |||||
$foreign_column, | |||||
$key_method, | |||||
$where); | |||||
if (!$relatives) { | |||||
return null; | |||||
} | |||||
if (count($relatives) > 1) { | |||||
throw new AphrontCountQueryException( | |||||
pht( | |||||
'More than one result from %s!', | |||||
__FUNCTION__.'()')); | |||||
} | |||||
return reset($relatives); | |||||
} | |||||
final public function putInSet(LiskDAOSet $set) { | |||||
$this->inSet = $set; | |||||
return $this; | |||||
} | |||||
final protected function getInSet() { | |||||
return $this->inSet; | |||||
} | |||||
/* -( Examining Objects )-------------------------------------------------- */ | /* -( Examining Objects )-------------------------------------------------- */ | ||||
/** | /** | ||||
* Set unique ID identifying this object. You normally don't need to call this | * Set unique ID identifying this object. You normally don't need to call this | ||||
* method unless with `IDS_MANUAL`. | * method unless with `IDS_MANUAL`. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 1,225 Lines • Show Last 20 Lines |