diff --git a/src/applications/drydock/query/DrydockBlueprintQuery.php b/src/applications/drydock/query/DrydockBlueprintQuery.php --- a/src/applications/drydock/query/DrydockBlueprintQuery.php +++ b/src/applications/drydock/query/DrydockBlueprintQuery.php @@ -4,6 +4,7 @@ private $ids; private $phids; + private $blueprintClasses; private $datasourceQuery; public function withIDs(array $ids) { @@ -16,63 +17,89 @@ return $this; } + public function withBlueprintClasses(array $classes) { + $this->blueprintClasses = $classes; + return $this; + } + public function withDatasourceQuery($query) { $this->datasourceQuery = $query; return $this; } + public function newResultObject() { + return new DrydockBlueprint(); + } + protected function loadPage() { - $table = new DrydockBlueprint(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT blueprint.* FROM %T blueprint %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - $blueprints = $table->loadAllFromArray($data); - - $implementations = - DrydockBlueprintImplementation::getAllBlueprintImplementations(); - - foreach ($blueprints as $blueprint) { - if (array_key_exists($blueprint->getClassName(), $implementations)) { - $blueprint->attachImplementation( - $implementations[$blueprint->getClassName()]); + return $this->loadStandardPage($this->newResultObject()); + } + + protected function willFilterPage(array $blueprints) { + $impls = DrydockBlueprintImplementation::getAllBlueprintImplementations(); + foreach ($blueprints as $key => $blueprint) { + $impl = idx($impls, $blueprint->getClassName()); + if (!$impl) { + $this->didRejectResult($blueprint); + unset($blueprints[$key]); + continue; } + $impl = clone $impl; + $blueprint->attachImplementation($impl); } return $blueprints; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } if ($this->datasourceQuery !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'blueprintName LIKE %>', $this->datasourceQuery); } - return $this->formatWhereClause($where); + if ($this->blueprintClasses !== null) { + $where[] = qsprintf( + $conn, + 'className IN (%Ls)', + $this->blueprintClasses); + } + + return $where; + } + + public function getOrderableColumns() { + // TODO: Blueprints implement CustomFields, but can not be ordered by + // custom field classes because the custom fields are not global. There + // is no graceful way to handle this in ApplicationSearch at the moment. + // Just brute force around it until we can clean this up. + + return array( + 'id' => array( + 'table' => $this->getPrimaryTableAlias(), + 'column' => 'id', + 'reverse' => false, + 'type' => 'int', + 'unique' => true, + ), + ); } } diff --git a/src/applications/drydock/query/DrydockLeaseQuery.php b/src/applications/drydock/query/DrydockLeaseQuery.php --- a/src/applications/drydock/query/DrydockLeaseQuery.php +++ b/src/applications/drydock/query/DrydockLeaseQuery.php @@ -28,15 +28,15 @@ return $this; } - public function newResultObject() { - return new DrydockLease(); - } - public function withDatasourceQuery($query) { $this->datasourceQuery = $query; return $this; } + public function newResultObject() { + return new DrydockLease(); + } + protected function loadPage() { return $this->loadStandardPage($this->newResultObject()); } diff --git a/src/applications/drydock/query/DrydockResourceQuery.php b/src/applications/drydock/query/DrydockResourceQuery.php --- a/src/applications/drydock/query/DrydockResourceQuery.php +++ b/src/applications/drydock/query/DrydockResourceQuery.php @@ -39,71 +39,82 @@ return $this; } - protected function loadPage() { - $table = new DrydockResource(); - $conn_r = $table->establishConnection('r'); + public function newResultObject() { + return new DrydockResource(); + } - $data = queryfx_all( - $conn_r, - 'SELECT resource.* FROM %T resource %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); + protected function loadPage() { + return $this->loadStandardPage($this->newResultObject()); + } - $resources = $table->loadAllFromArray($data); + protected function willFilterPage(array $resources) { + $blueprint_phids = mpull($resources, 'getBlueprintPHID'); + + $blueprints = id(new DrydockBlueprintQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs($blueprint_phids) + ->execute(); + $blueprints = mpull($blueprints, null, 'getPHID'); + + foreach ($resources as $key => $resource) { + $blueprint = idx($blueprints, $resource->getBlueprintPHID()); + if (!$blueprint) { + $this->didRejectResult($resource); + unset($resources[$key]); + continue; + } + $resource->attachBlueprint($blueprint); + } return $resources; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } if ($this->types !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'type IN (%Ls)', $this->types); } if ($this->statuses !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'status IN (%Ls)', $this->statuses); } if ($this->blueprintPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'blueprintPHID IN (%Ls)', $this->blueprintPHIDs); } if ($this->datasourceQuery !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'name LIKE %>', $this->datasourceQuery); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } } diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php --- a/src/applications/drydock/storage/DrydockResource.php +++ b/src/applications/drydock/storage/DrydockResource.php @@ -14,7 +14,7 @@ protected $capabilities = array(); protected $ownerPHID; - private $blueprint; + private $blueprint = self::ATTACHABLE; protected function getConfiguration() { return array( @@ -65,16 +65,24 @@ } public function getBlueprint() { - // TODO: Policy stuff. - if (empty($this->blueprint)) { - $blueprint = id(new DrydockBlueprint()) - ->loadOneWhere('phid = %s', $this->blueprintPHID); - $this->blueprint = $blueprint->getImplementation(); - } - return $this->blueprint; + return $this->assertAttached($this->blueprint); + } + + public function attachBlueprint(DrydockBlueprint $blueprint) { + $this->blueprint = $blueprint; + return $this; + } + + public function canAllocateLease(DrydockLease $lease) { + return $this->getBlueprint()->canAllocateLeaseOnResource( + $this, + $lease); } public function closeResource() { + + // TODO: This is super broken and will race other lease writers! + $this->openTransaction(); $statuses = array( DrydockLeaseStatus::STATUS_PENDING,