From 334bebddd0a7caf33be31445ca3e10b4c49f3e1b Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 7 May 2020 10:01:17 -0400 Subject: [PATCH] APIv4 - Remove implicit multi-joins These were actually run as a separate query and "joined" to the main results array in PHP. Removing them to make way for supporting explicit multi-joins which will use SQL. --- Civi/Api4/Event/Events.php | 5 - .../Subscriber/ContactSchemaMapSubscriber.php | 73 ---- .../Subscriber/PostSelectQuerySubscriber.php | 335 ------------------ Civi/Api4/Query/Api4SelectQuery.php | 84 +---- Civi/Api4/Service/Schema/Joiner.php | 21 +- tests/phpunit/api/v4/Action/FkJoinTest.php | 36 -- .../Query/Api4SelectQueryComplexJoinTest.php | 110 ------ .../api/v4/Query/Api4SelectQueryTest.php | 43 --- .../phpunit/api/v4/Query/OneToOneJoinTest.php | 4 +- .../api/v4/Query/SelectQueryMultiJoinTest.php | 32 +- 10 files changed, 30 insertions(+), 713 deletions(-) delete mode 100644 Civi/Api4/Event/Subscriber/ContactSchemaMapSubscriber.php delete mode 100644 Civi/Api4/Event/Subscriber/PostSelectQuerySubscriber.php delete mode 100644 tests/phpunit/api/v4/Query/Api4SelectQueryComplexJoinTest.php diff --git a/Civi/Api4/Event/Events.php b/Civi/Api4/Event/Events.php index bb866e287b..4264ef2ff5 100644 --- a/Civi/Api4/Event/Events.php +++ b/Civi/Api4/Event/Events.php @@ -36,9 +36,4 @@ class Events { */ const SCHEMA_MAP_BUILD = 'api.schema_map.build'; - /** - * Alter query results of APIv4 select query - */ - const POST_SELECT_QUERY = 'api.select_query.post'; - } diff --git a/Civi/Api4/Event/Subscriber/ContactSchemaMapSubscriber.php b/Civi/Api4/Event/Subscriber/ContactSchemaMapSubscriber.php deleted file mode 100644 index d41ab9f140..0000000000 --- a/Civi/Api4/Event/Subscriber/ContactSchemaMapSubscriber.php +++ /dev/null @@ -1,73 +0,0 @@ - 'onSchemaBuild', - ]; - } - - /** - * @param \Civi\Api4\Event\SchemaMapBuildEvent $event - */ - public function onSchemaBuild(SchemaMapBuildEvent $event) { - $schema = $event->getSchemaMap(); - $table = $schema->getTableByName('civicrm_contact'); - $this->addCreatedActivitiesLink($table); - $this->fixPreferredLanguageAlias($table); - } - - /** - * @param \Civi\Api4\Service\Schema\Table $table - */ - private function addCreatedActivitiesLink($table) { - $alias = 'created_activities'; - $joinable = new Joinable('civicrm_activity_contact', 'contact_id', $alias); - $joinable->addCondition($alias . '.record_type_id = 1'); - $joinable->setJoinType($joinable::JOIN_TYPE_ONE_TO_MANY); - $table->addTableLink('id', $joinable); - } - - /** - * @param \Civi\Api4\Service\Schema\Table $table - */ - private function fixPreferredLanguageAlias($table) { - foreach ($table->getExternalLinks() as $link) { - if ($link->getAlias() === 'languages') { - $link->setAlias('preferred_language'); - return; - } - } - } - -} diff --git a/Civi/Api4/Event/Subscriber/PostSelectQuerySubscriber.php b/Civi/Api4/Event/Subscriber/PostSelectQuerySubscriber.php deleted file mode 100644 index e21c2dd381..0000000000 --- a/Civi/Api4/Event/Subscriber/PostSelectQuerySubscriber.php +++ /dev/null @@ -1,335 +0,0 @@ - 'onPostQuery', - ]; - } - - /** - * @param \Civi\Api4\Event\PostSelectQueryEvent $event - */ - public function onPostQuery(PostSelectQueryEvent $event) { - $results = $event->getResults(); - $event->setResults($this->postRun($results, $event->getQuery())); - } - - /** - * @param array $results - * @param \Civi\Api4\Query\Api4SelectQuery $query - * - * @return array - */ - protected function postRun(array $results, Api4SelectQuery $query) { - if (empty($results)) { - return $results; - } - - FormattingUtil::formatOutputValues($results, $query->getApiFieldSpec(), $query->getEntity()); - - // Group the selects to avoid queries for each field - $groupedSelects = $this->getNtoManyJoinSelects($query); - foreach ($groupedSelects as $finalAlias => $selects) { - $joinPath = $query->getPathJoinTypes($selects[0]); - $selects = $this->formatSelects($finalAlias, $selects, $query); - $joinResults = $this->getJoinResults($query, $finalAlias, $selects); - $this->formatJoinResults($joinResults, $query, $finalAlias); - - // Insert join results into original result - foreach ($results as &$primaryResult) { - $baseId = $primaryResult['id']; - $filtered = array_filter($joinResults, function ($res) use ($baseId) { - return ($res['_base_id'] == $baseId); - }); - $filtered = array_values($filtered); - ArrayInsertionUtil::insert($primaryResult, $joinPath, $filtered); - } - } - - return array_values($results); - } - - /** - * @param array $joinResults - * @param \Civi\Api4\Query\Api4SelectQuery $query - * @param string $alias - */ - private function formatJoinResults(&$joinResults, $query, $alias) { - $join = $query->getJoinedTable($alias); - $fields = []; - foreach ($join->getEntityFields() as $field) { - $name = explode('.', $field->getName()); - $fields[array_pop($name)] = $field->toArray(); - } - if ($fields) { - FormattingUtil::formatOutputValues($joinResults, $fields, $join->getEntity()); - } - } - - /** - * Find only those joins that need to be handled by a separate query and weren't done in the main query. - * - * @param \Civi\Api4\Query\Api4SelectQuery $query - * - * @return array - */ - private function getNtoManyJoinSelects(Api4SelectQuery $query) { - $joinedDotSelects = array_filter( - $query->getSelect(), - function ($select) use ($query) { - return strpos($select, '.') && array_filter($query->getPathJoinTypes($select)); - } - ); - - $selects = []; - // group related selects by alias so they can be executed in one query - foreach ($joinedDotSelects as $select) { - $parts = explode('.', $select); - $finalAlias = $parts[count($parts) - 2]; - $selects[$finalAlias][] = $select; - } - - // sort by depth, e.g. email selects should be done before email.location - uasort($selects, function ($a, $b) { - $aFirst = $a[0]; - $bFirst = $b[0]; - return substr_count($aFirst, '.') > substr_count($bFirst, '.'); - }); - - return $selects; - } - - /** - * @param array $selects - * @param $serializationType - * @param \Civi\Api4\Query\Api4SelectQuery $query - * - * @return array - */ - private function getResultsForSerializedField( - array $selects, - $serializationType, - Api4SelectQuery $query - ) { - // Get the alias (Selects are grouped and all target the same table) - $sampleField = current($selects); - $alias = strstr($sampleField, '.', TRUE); - - // Fetch the results with the serialized field - $selects['serialized'] = $query::MAIN_TABLE_ALIAS . '.' . $alias; - $serializedResults = $this->runWithNewSelects($selects, $query); - $newResults = []; - - // Create a new results array, with a separate entry for each option value - foreach ($serializedResults as $result) { - $optionValues = \CRM_Core_DAO::unSerializeField( - $result['serialized'], - $serializationType - ); - unset($result['serialized']); - foreach ($optionValues as $value) { - $newResults[] = array_merge($result, ['value' => $value]); - } - } - - $optionValueValues = array_unique(array_column($newResults, 'value')); - $optionValues = $this->getOptionValuesFromValues( - $selects, - $query, - $optionValueValues - ); - $valueField = $alias . '.value'; - - // Index by value - foreach ($optionValues as $key => $subResult) { - $optionValues[$subResult['value']] = $subResult; - unset($subResult[$key]); - - // Exclude 'value' if not in original selects - if (!in_array($valueField, $selects)) { - unset($optionValues[$subResult['value']]['value']); - } - } - - // Replace serialized with the sub-select results - foreach ($newResults as &$result) { - $result = array_merge($result, $optionValues[$result['value']]); - unset($result['value']); - } - - return $newResults; - } - - /** - * Prepares selects for the subquery to fetch join results - * - * @param string $alias - * @param array $selects - * @param \Civi\Api4\Query\Api4SelectQuery $query - * - * @return array - */ - private function formatSelects($alias, $selects, Api4SelectQuery $query) { - $mainAlias = $query::MAIN_TABLE_ALIAS; - $selectFields = []; - - foreach ($selects as $select) { - $selectAlias = str_replace('`', '', $query->getField($select)['sql_name']); - $fieldAlias = substr($select, strrpos($select, '.') + 1); - $selectFields[$fieldAlias] = $selectAlias; - } - - $firstSelect = $selects[0]; - $pathParts = explode('.', $firstSelect); - $numParts = count($pathParts); - $parentAlias = $numParts > 2 ? $pathParts[$numParts - 3] : $mainAlias; - - $selectFields['id'] = sprintf('%s.id', $alias); - $selectFields['_parent_id'] = $parentAlias . '.id'; - $selectFields['_base_id'] = $mainAlias . '.id'; - - return $selectFields; - } - - /** - * @param array $selects - * @param \Civi\Api4\Query\Api4SelectQuery $query - * - * @return array - */ - private function runWithNewSelects(array $selects, Api4SelectQuery $query) { - $aliasedSelects = array_map(function ($field, $alias) { - return sprintf('%s as "%s"', $field, $alias); - }, $selects, array_keys($selects)); - - $newSelect = sprintf('SELECT DISTINCT %s', implode(", ", $aliasedSelects)); - $sql = $query->getQuery()->toSQL(); - // Replace the "SELECT" clause - $sql = $newSelect . substr($sql, strpos($sql, "\nFROM")); - - if (is_array($query->debugOutput)) { - $query->debugOutput['sql'][] = $sql; - } - - $relatedResults = []; - $resultDAO = \CRM_Core_DAO::executeQuery($sql); - while ($resultDAO->fetch()) { - $relatedResult = []; - foreach ($selects as $alias => $column) { - $returnName = $alias; - $alias = str_replace('.', '_', $alias); - if (property_exists($resultDAO, $alias)) { - $relatedResult[$returnName] = $resultDAO->$alias; - } - }; - $relatedResults[] = $relatedResult; - } - - return $relatedResults; - } - - /** - * @param \Civi\Api4\Query\Api4SelectQuery $query - * @param $alias - * @param $selects - * @return array - */ - protected function getJoinResults(Api4SelectQuery $query, $alias, $selects) { - $apiFieldSpec = $query->getApiFieldSpec(); - if (!empty($apiFieldSpec[$alias]['serialize'])) { - $type = $apiFieldSpec[$alias]['serialize']; - $joinResults = $this->getResultsForSerializedField($selects, $type, $query); - } - else { - $joinResults = $this->runWithNewSelects($selects, $query); - } - - // Remove results with no matching entries - $joinResults = array_filter($joinResults, function ($result) { - return !empty($result['id']); - }); - - return $joinResults; - } - - /** - * Get all the option_value values required in the query - * - * @param array $selects - * @param \Civi\Api4\Query\Api4SelectQuery $query - * @param array $values - * - * @return array - */ - private function getOptionValuesFromValues( - array $selects, - Api4SelectQuery $query, - array $values - ) { - $sampleField = current($selects); - $alias = strstr($sampleField, '.', TRUE); - - // Get the option value table that was joined - $relatedTable = NULL; - foreach ($query->getJoinedTables() as $joinedTable) { - if ($joinedTable->getAlias() === $alias) { - $relatedTable = $joinedTable; - } - } - - // We only want subselects related to the joined table - $subSelects = array_filter($selects, function ($select) use ($alias) { - return strpos($select, $alias) === 0; - }); - - // Fetch all related option_value entries - $valueField = $alias . '.value'; - $subSelects[] = $valueField; - $tableName = $relatedTable->getTargetTable(); - $conditions = $relatedTable->getExtraJoinConditions(); - $conditions[] = $valueField . ' IN ("' . implode('", "', $values) . '")'; - $subQuery = new \CRM_Utils_SQL_Select($tableName . ' ' . $alias); - $subQuery->where($conditions); - $subQuery->select($subSelects); - $subResults = $subQuery->execute()->fetchAll(); - - return $subResults; - } - -} diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php index 63cba4e280..26e12fedbc 100644 --- a/Civi/Api4/Query/Api4SelectQuery.php +++ b/Civi/Api4/Query/Api4SelectQuery.php @@ -12,8 +12,6 @@ namespace Civi\Api4\Query; use Civi\API\SelectQuery; -use Civi\Api4\Event\Events; -use Civi\Api4\Event\PostSelectQueryEvent; use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable; use Civi\Api4\Service\Schema\Joinable\Joinable; use Civi\Api4\Utils\FormattingUtil; @@ -133,24 +131,21 @@ class Api4SelectQuery extends SelectQuery { $this->debugOutput['sql'][] = $sql; } $query = \CRM_Core_DAO::executeQuery($sql); - $i = 0; while ($query->fetch()) { - $id = $query->id ?? $i++; if (in_array('row_count', $this->select)) { $results[]['row_count'] = (int) $query->c; break; } - $results[$id] = []; + $result = []; foreach ($this->selectAliases as $alias => $expr) { $returnName = $alias; $alias = str_replace('.', '_', $alias); - $results[$id][$returnName] = property_exists($query, $alias) ? $query->$alias : NULL; + $result[$returnName] = property_exists($query, $alias) ? $query->$alias : NULL; } + $results[] = $result; } - $event = new PostSelectQueryEvent($results, $this); - \Civi::dispatcher()->dispatch(Events::POST_SELECT_QUERY, $event); - - return $event->getResults(); + FormattingUtil::formatOutputValues($results, $this->getApiFieldSpec(), $this->getEntity()); + return $results; } protected function buildSelectClause() { @@ -173,7 +168,7 @@ class Api4SelectQuery extends SelectQuery { }); foreach ($wildFields as $item) { $pos = array_search($item, array_values($this->select)); - $this->joinFK($item); + $this->autoJoinFK($item); $matches = SelectUtil::getMatchingFields($item, array_keys($this->apiFieldSpec)); array_splice($this->select, $pos, 1, $matches); } @@ -192,9 +187,6 @@ class Api4SelectQuery extends SelectQuery { } $valid = FALSE; } - elseif ($field['is_many']) { - $valid = FALSE; - } } if ($valid) { $alias = $expr->getAlias(); @@ -388,7 +380,7 @@ class Api4SelectQuery extends SelectQuery { $fieldName = $col ? substr($expr, 0, $col) : $expr; // Perform join if field not yet available - this will add it to apiFieldSpec if (!isset($this->apiFieldSpec[$fieldName]) && strpos($fieldName, '.')) { - $this->joinFK($fieldName); + $this->autoJoinFK($fieldName); } $field = $this->apiFieldSpec[$fieldName] ?? NULL; if ($strict && !$field) { @@ -399,13 +391,13 @@ class Api4SelectQuery extends SelectQuery { } /** - * Joins a path and adds all fields in the joined eneity to apiFieldSpec + * Joins a path and adds all fields in the joined entity to apiFieldSpec * * @param $key * @throws \API_Exception * @throws \Exception */ - protected function joinFK($key) { + protected function autoJoinFK($key) { if (isset($this->apiFieldSpec[$key])) { return; } @@ -418,20 +410,12 @@ class Api4SelectQuery extends SelectQuery { array_pop($pathArray); $pathString = implode('.', $pathArray); - if (!$joiner->canJoin($this, $pathString)) { + if (!$joiner->canAutoJoin($this->getFrom(), $pathString)) { return; } $joinPath = $joiner->join($this, $pathString); - $isMany = FALSE; - foreach ($joinPath as $joinable) { - if ($joinable->getJoinType() === Joinable::JOIN_TYPE_ONE_TO_MANY) { - $isMany = TRUE; - } - } - - /** @var \Civi\Api4\Service\Schema\Joinable\Joinable $lastLink */ $lastLink = array_pop($joinPath); // Custom field names are already prefixed @@ -447,7 +431,6 @@ class Api4SelectQuery extends SelectQuery { $fieldArray['sql_name'] = '`' . $lastLink->getAlias() . '`.`' . $fieldArray['column_name'] . '`'; $fieldArray['is_custom'] = $isCustom; $fieldArray['is_join'] = TRUE; - $fieldArray['is_many'] = $isMany; $this->addSpecField($prefix . $fieldArray['name'], $fieldArray); } } @@ -611,51 +594,6 @@ class Api4SelectQuery extends SelectQuery { } } - /** - * Checks if a field either belongs to the main entity or is joinable 1-to-1. - * - * Used to determine if a field can be added to the SELECT of the main query, - * or if it must be fetched post-query. - * - * @param string $fieldPath - * @return bool - */ - public function isOneToOneField(string $fieldPath) { - return strpos($fieldPath, '.') === FALSE || !array_filter($this->getPathJoinTypes($fieldPath)); - } - - /** - * Separates a string like 'emails.location_type.label' into an array, where - * each value in the array tells whether it is 1-1 or 1-n join type - * - * @param string $pathString - * Dot separated path to the field - * - * @return array - * Index is table alias and value is boolean whether is 1-to-many join - */ - public function getPathJoinTypes($pathString) { - $pathParts = explode('.', $pathString); - // remove field - array_pop($pathParts); - $path = []; - $query = $this; - $isMultipleChecker = function($alias) use ($query) { - foreach ($query->getJoinedTables() as $table) { - if ($table->getAlias() === $alias) { - return $table->getJoinType() === Joinable::JOIN_TYPE_ONE_TO_MANY; - } - } - return FALSE; - }; - - foreach ($pathParts as $part) { - $path[$part] = $isMultipleChecker($part); - } - - return $path; - } - /** * @param $path * @param $field @@ -667,7 +605,7 @@ class Api4SelectQuery extends SelectQuery { return; } $defaults = []; - $defaults['is_custom'] = $defaults['is_join'] = $defaults['is_many'] = FALSE; + $defaults['is_custom'] = $defaults['is_join'] = FALSE; $field += $defaults; $this->apiFieldSpec[$path] = $field; } diff --git a/Civi/Api4/Service/Schema/Joiner.php b/Civi/Api4/Service/Schema/Joiner.php index 6333e14a77..58bb850ce6 100644 --- a/Civi/Api4/Service/Schema/Joiner.php +++ b/Civi/Api4/Service/Schema/Joiner.php @@ -72,20 +72,33 @@ class Joiner { } /** - * @param \Civi\Api4\Query\Api4SelectQuery $query + * Determines if path string points to a simple n-1 join that can be automatically added + * + * @param string $baseTable * @param $joinPath * * @return bool */ - public function canJoin(Api4SelectQuery $query, $joinPath) { - return !empty($this->getPath($query->getFrom(), $joinPath)); + public function canAutoJoin($baseTable, $joinPath) { + try { + $path = $this->getPath($baseTable, $joinPath); + foreach ($path as $joinable) { + if ($joinable->getJoinType() === $joinable::JOIN_TYPE_ONE_TO_MANY) { + return FALSE; + } + } + return TRUE; + } + catch (\Exception $e) { + return FALSE; + } } /** * @param string $baseTable * @param string $joinPath * - * @return array + * @return \Civi\Api4\Service\Schema\Joinable\Joinable[] * @throws \Exception */ protected function getPath($baseTable, $joinPath) { diff --git a/tests/phpunit/api/v4/Action/FkJoinTest.php b/tests/phpunit/api/v4/Action/FkJoinTest.php index 66e2c9dfe6..f23109a479 100644 --- a/tests/phpunit/api/v4/Action/FkJoinTest.php +++ b/tests/phpunit/api/v4/Action/FkJoinTest.php @@ -55,40 +55,4 @@ class FkJoinTest extends UnitTestCase { $this->assertCount(1, $results); } - public function testActivityContactJoin() { - $results = Activity::get() - ->setCheckPermissions(FALSE) - ->addSelect('assignees.id') - ->addSelect('assignees.first_name') - ->addSelect('assignees.display_name') - ->addWhere('assignees.first_name', '=', 'Phoney') - ->execute(); - - $firstResult = $results->first(); - - $this->assertCount(1, $results); - $this->assertTrue(is_array($firstResult['assignees'])); - - $firstAssignee = array_shift($firstResult['assignees']); - $this->assertEquals($firstAssignee['first_name'], 'Phoney'); - } - - public function testContactPhonesJoin() { - $testContact = $this->getReference('test_contact_1'); - $testPhone = $this->getReference('test_phone_1'); - - $results = Contact::get() - ->setCheckPermissions(FALSE) - ->addSelect('phones.phone') - ->addWhere('id', '=', $testContact['id']) - ->addWhere('phones.location_type_id:name', '=', 'Home') - ->execute() - ->first(); - - $this->assertArrayHasKey('phones', $results); - $this->assertCount(1, $results['phones']); - $firstPhone = array_shift($results['phones']); - $this->assertEquals($testPhone['phone'], $firstPhone['phone']); - } - } diff --git a/tests/phpunit/api/v4/Query/Api4SelectQueryComplexJoinTest.php b/tests/phpunit/api/v4/Query/Api4SelectQueryComplexJoinTest.php deleted file mode 100644 index eaae446b40..0000000000 --- a/tests/phpunit/api/v4/Query/Api4SelectQueryComplexJoinTest.php +++ /dev/null @@ -1,110 +0,0 @@ -cleanup(['tablesToTruncate' => $relatedTables]); - $this->loadDataSet('SingleContact'); - return parent::setUpHeadless(); - } - - public function testWithComplexRelatedEntitySelect() { - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); $query->select[] = 'id'; - $query->select[] = 'display_name'; - $query->select[] = 'phones.*_id'; - $query->select[] = 'emails.email'; - $query->select[] = 'emails.location_type_id:name'; - $query->select[] = 'created_activities.contact_id'; - $query->select[] = 'created_activities.activity.subject'; - $query->select[] = 'created_activities.activity.activity_type_id:name'; - $query->where[] = ['first_name', '=', 'Single']; - $query->where[] = ['id', '=', $this->getReference('test_contact_1')['id']]; - $results = $query->run(); - - $testActivities = [ - $this->getReference('test_activity_1'), - $this->getReference('test_activity_2'), - ]; - $activitySubjects = array_column($testActivities, 'subject'); - - $this->assertCount(1, $results); - $firstResult = array_shift($results); - $this->assertArrayHasKey('created_activities', $firstResult); - $firstCreatedActivity = array_shift($firstResult['created_activities']); - $this->assertArrayHasKey('activity', $firstCreatedActivity); - $firstActivity = $firstCreatedActivity['activity']; - $this->assertContains($firstActivity['subject'], $activitySubjects); - $this->assertArrayHasKey('activity_type_id:name', $firstActivity); - - $this->assertArrayHasKey('location_type_id:name', $firstResult['emails'][0]); - $this->assertArrayHasKey('location_type_id', $firstResult['phones'][0]); - $this->assertArrayHasKey('id', $firstResult['phones'][0]); - $this->assertArrayNotHasKey('phone', $firstResult['phones'][0]); - } - - public function testWithSelectOfOrphanDeepValues() { - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); $query->select[] = 'id'; - $query->select[] = 'first_name'; - // emails not selected - $query->select[] = 'emails.location_type.name'; - $results = $query->run(); - $firstResult = array_shift($results); - - $this->assertEmpty($firstResult['emails']); - } - - public function testOrderDoesNotMatter() { - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); - $query->select[] = 'id'; - $query->select[] = 'first_name'; - // before emails selection - $query->select[] = 'emails.location_type_id:name'; - $query->select[] = 'emails.email'; - $query->where[] = ['emails.email', 'IS NOT NULL']; - $results = $query->run(); - $firstResult = array_shift($results); - - $this->assertNotEmpty($firstResult['emails'][0]['location_type_id:name']); - } - -} diff --git a/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php b/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php index 3a11b5e8b0..a628b89106 100644 --- a/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php +++ b/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php @@ -48,35 +48,6 @@ class Api4SelectQueryTest extends UnitTestCase { return parent::setUpHeadless(); } - public function testWithSingleWhereJoin() { - $phoneNum = $this->getReference('test_phone_1')['phone']; - - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); - $query->where[] = ['phones.phone', '=', $phoneNum]; - $results = $query->run(); - - $this->assertCount(1, $results); - } - - public function testOneToManyJoin() { - $phoneNum = $this->getReference('test_phone_1')['phone']; - - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); - $query->select[] = 'id'; - $query->select[] = 'first_name'; - $query->select[] = 'phones.phone'; - $query->where[] = ['phones.phone', '=', $phoneNum]; - $results = $query->run(); - - $this->assertCount(1, $results); - $firstResult = array_shift($results); - $this->assertArrayHasKey('phones', $firstResult); - $firstPhone = array_shift($firstResult['phones']); - $this->assertEquals($phoneNum, $firstPhone['phone']); - } - public function testManyToOneJoin() { $phoneNum = $this->getReference('test_phone_1')['phone']; $contact = $this->getReference('test_contact_1'); @@ -95,20 +66,6 @@ class Api4SelectQueryTest extends UnitTestCase { $this->assertEquals($contact['display_name'], $firstResult['contact.display_name']); } - public function testOneToManyMultipleJoin() { - $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); - $query = new Api4SelectQuery($api); - $query->select[] = 'id'; - $query->select[] = 'first_name'; - $query->select[] = 'phones.phone'; - $query->where[] = ['first_name', '=', 'Phoney']; - $results = $query->run(); - $result = array_pop($results); - - $this->assertEquals('Phoney', $result['first_name']); - $this->assertCount(2, $result['phones']); - } - public function testInvaidSort() { $api = \Civi\API\Request::create('Contact', 'get', ['version' => 4, 'checkPermissions' => FALSE]); $query = new Api4SelectQuery($api); diff --git a/tests/phpunit/api/v4/Query/OneToOneJoinTest.php b/tests/phpunit/api/v4/Query/OneToOneJoinTest.php index 138034c77b..416289db2c 100644 --- a/tests/phpunit/api/v4/Query/OneToOneJoinTest.php +++ b/tests/phpunit/api/v4/Query/OneToOneJoinTest.php @@ -14,7 +14,6 @@ * * @package CRM * @copyright CiviCRM LLC https://civicrm.org/licensing - * $Id$ * */ @@ -53,8 +52,7 @@ class OneToOneJoinTest extends UnitTestCase { ->addSelect('preferred_language:label') ->addSelect('last_name') ->execute() - ->indexBy('last_name') - ->getArrayCopy(); + ->indexBy('last_name'); $this->assertEquals($contacts['One']['preferred_language:label'], 'Armenian'); $this->assertEquals($contacts['Two']['preferred_language:label'], 'Basque'); diff --git a/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php b/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php index 4f0f22416d..d8af222c68 100644 --- a/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php +++ b/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php @@ -21,7 +21,6 @@ namespace api\v4\Query; -use Civi\Api4\Contact; use Civi\Api4\Email; use api\v4\UnitTestCase; @@ -38,40 +37,11 @@ class SelectQueryMultiJoinTest extends UnitTestCase { return parent::setUpHeadless(); } - public function testOneToManySelect() { - $results = Contact::get() - ->addSelect('emails.email') - ->execute() - ->indexBy('id') - ->getArrayCopy(); - - $firstContactId = $this->getReference('test_contact_1')['id']; - $secondContactId = $this->getReference('test_contact_2')['id']; - - $firstContact = $results[$firstContactId]; - $secondContact = $results[$secondContactId]; - $firstContactEmails = array_column($firstContact['emails'], 'email'); - $secondContactEmails = array_column($secondContact['emails'], 'email'); - - $expectedFirstEmails = [ - 'test_contact_one_home@fakedomain.com', - 'test_contact_one_work@fakedomain.com', - ]; - $expectedSecondEmails = [ - 'test_contact_two_home@fakedomain.com', - 'test_contact_two_work@fakedomain.com', - ]; - - $this->assertEquals($expectedFirstEmails, $firstContactEmails); - $this->assertEquals($expectedSecondEmails, $secondContactEmails); - } - public function testManyToOneSelect() { $results = Email::get() ->addSelect('contact.display_name') ->execute() - ->indexBy('id') - ->getArrayCopy(); + ->indexBy('id'); $firstEmail = $this->getReference('test_email_1'); $secondEmail = $this->getReference('test_email_2'); -- 2.25.1