public function testBetweenNumbers() { $this->list->filter(new Between("FavouriteNumber", 10, 20)); $this->assertCount(2, $this->list); $this->assertEquals("John", $this->list[0]->Forename); $this->assertEquals("Mary", $this->list[1]->Forename); }
public function testCanFilterOnRelatedModelProperties() { $gcd = new Company(); $gcd->CompanyName = "GCD"; $gcd->save(); $widgetCo = new Company(); $widgetCo->CompanyName = "Widgets"; $widgetCo->save(); $example = new User(); $example->Username = "******"; $widgetCo->Users->Append($example); $example = new User(); $example->Username = "******"; $gcd->Users->Append($example); $example = new User(); $example->Username = "******"; $widgetCo->Users->Append($example); $example = new User(); $example->Username = "******"; $gcd->Users->Append($example); $list = new Collection("Rhubarb\\Stem\\Tests\\Fixtures\\User"); $list->filter(new Equals("Company.CompanyName", "GCD")); $this->assertCount(2, $list); $this->assertEquals("b", $list[0]->Username); $this->assertEquals("d", $list[1]->Username); }
public function testFiltersOnOtherColumn() { $filter = new \Rhubarb\Stem\Filters\LessThan("Forename", "@{Surname}", true); $this->list->filter($filter); $this->assertCount(1, $this->list); $this->assertEquals("Morris", $this->list[0]->Surname); }
public function testFiltersMatchingRows() { $filter = new \Rhubarb\Stem\Filters\Equals("Forename", "Tom"); $this->list->filter($filter); $this->assertCount(1, $this->list); $this->assertEquals("Thumb", $this->list[0]->Surname); }
public function calculateByIteration(Collection $collection) { // If the list hasn't been fetched, sizeof() will still calculate it with an Aggregate, // so we need for force the list to be fetched now so the sizeof() can calculate by iteration $collection->fetchList(); return sizeof($collection); }
public function testSumIsCalculatedOnRepository() { $examples = new Collection("Company"); list($sumTotal) = $examples->calculateAggregates([new MySqlCountDistinct("CompanyName")]); $this->assertEquals(2, $sumTotal); $lastStatement = MySql::getPreviousStatement(false); $this->assertContains("COUNT( DISTINCT `CompanyName` ) AS `DistinctCountOfCompanyName`", $lastStatement); }
public function testSumIsCalculatedOnRepository() { $examples = new Collection("Company"); list($sumTotal) = $examples->calculateAggregates([new MySqlAverage("Balance")]); $this->assertEquals(3, $sumTotal); $lastStatement = MySql::getPreviousStatement(false); $this->assertContains("AVG( `Balance` ) AS `AverageOfBalance`", $lastStatement); }
public function testFiltersAlpha() { $filter = new \Rhubarb\Stem\Filters\GreaterThan("Forename", "Mary", true); $this->list->filter($filter); $this->assertCount(2, $this->list); $filter = new \Rhubarb\Stem\Filters\GreaterThan("Forename", "Mary", false); $this->list->filter($filter); $this->assertCount(1, $this->list); $this->assertContains("Tom", $this->list[0]->Forename); }
/** * Returns an array of unique identifiers to filter from the list. * * This will be an empty array if a repository has used this filter to do it's filtering. * * @param Collection $list The data list to filter. * @return array */ public final function getUniqueIdentifiersToFilter(Collection $list) { if ($this->wasFilteredByRepository()) { return []; } $list->disableRanging(); $filtered = $this->doGetUniqueIdentifiersToFilter($list); $list->enableRanging(); return $filtered; }
public function testFiltersCaseSensitive() { $filter = new \Rhubarb\Stem\Filters\Contains("Forename", "Jo", true); $this->list->filter($filter); $this->assertCount(1, $this->list); $this->assertContains("John", $this->list[0]->Forename); $filter = new \Rhubarb\Stem\Filters\Contains("Forename", "oH", true); $this->list->filter($filter); $this->assertCount(0, $this->list); }
public function testFiltersCaseSensitive() { $filter = new \Rhubarb\Stem\Filters\EndsWith("Forename", "ry", true); $this->list->filter($filter); $this->assertCount(1, $this->list); $this->assertContains("Mary", $this->list[0]->Forename); $filter = new \Rhubarb\Stem\Filters\EndsWith("Forename", "RY", true); $this->list->filter($filter); $this->assertCount(0, $this->list); }
public function testFilters() { $filter = new \Rhubarb\Stem\Filters\OneOf("Forename", ["Cuthbert", "Dibble", "Grub", "Pugh"]); $this->list->filter($filter); $this->assertCount(5, $this->list); $this->assertContains("Pugh", $this->list[0]->Forename); $filter = new \Rhubarb\Stem\Filters\OneOf("Forename", ["Cuthbert", "Dibble", "Grub"]); $this->list->filter($filter); $this->assertCount(3, $this->list); $this->assertContains("Cuthbert", $this->list[0]->Forename); }
/** * Converts the comparison value used in the constructor to one which can be compared against that returned * by the relevant model. * * @param $rawComparisonValue * @param Collection $list * @return mixed */ protected final function getTransformedComparisonValue($rawComparisonValue, Collection $list) { $exampleObject = SolutionSchema::getModel($list->getModelClassName()); $columnSchema = $exampleObject->getColumnSchemaForColumnReference($this->columnName); if ($columnSchema != null) { $closure = $columnSchema->getTransformIntoModelData(); if ($closure !== null) { $rawComparisonValue = $closure($rawComparisonValue); } } return $rawComparisonValue; }
function testFiltersWithGroupedGroup() { $filterGroup1 = new \Rhubarb\Stem\Filters\Group("And"); $filterGroup1->addFilters(new \Rhubarb\Stem\Filters\Contains("Forename", "Jo", true), new \Rhubarb\Stem\Filters\Contains("Surname", "Jo", true)); $filterGroup2 = new \Rhubarb\Stem\Filters\Group("Or"); $filterGroup2->addFilters(new \Rhubarb\Stem\Filters\Contains("Surname", "Luc", true), new \Rhubarb\Stem\Filters\LessThan("DateOfBirth", "1980-01-01", true)); $filterGroup = new \Rhubarb\Stem\Filters\Group("Or"); $filterGroup->addFilters($filterGroup1, $filterGroup2); $this->list->Not($filterGroup); $this->assertCount(1, $this->list); $this->assertContains("Smithe", $this->list[0]->Surname); }
public function testSumIsCalculatedOnRepository() { $examples = new Collection("Company"); list($sumTotal) = $examples->calculateAggregates([new MySqlSum("Balance")]); $this->assertEquals(6, $sumTotal); $lastStatement = MySql::getPreviousStatement(false); $this->assertContains("SUM( `Balance` ) AS `SumOfBalance`", $lastStatement); $examples = new Collection("Company"); $examples->filter(new GreaterThan("Balance", 1)); list($sumTotal) = $examples->calculateAggregates(new MySqlSum("Balance")); $this->assertEquals(5, $sumTotal); $lastStatement = MySql::getPreviousStatement(false); $this->assertContains("SUM( `Balance` ) AS `SumOfBalance`", $lastStatement); $this->assertContains("WHERE `tblCompany`.`Balance` > ", $lastStatement); }
protected function getCurrentlyAvailableSelectionItems() { if ($this->Phrase == "") { return []; } $class = $this->modelClassName; $list = new Collection($class); $filter = $this->getCollectionFilter($this->Phrase); $list->filter($filter); $results = []; foreach ($list as $item) { $result = $this->makeItem($item->getUniqueIdentifier(), $item->getLabel(), $this->getDataForItem($item)); $results[] = $result; } return $results; }
public function login($username, $password) { // We don't allow spaces around our usernames and passwords $username = trim($username); $password = trim($password); if ($username == "") { throw new LoginFailedException(); } $list = new Collection($this->modelClassName); $list->filter(new Equals($this->usernameColumnName, $username)); if (!sizeof($list)) { throw new LoginFailedException(); } $hashProvider = HashProvider::getHashProvider(); // There should only be one user matching the username. It would be possible to support // unique *combinations* of username and password but it's a potential security issue and // could trip us up when supporting the project. if (sizeof($list) > 1) { throw new LoginFailedException(); } $user = $list[0]; $this->checkUserIsPermitted($user); // Test the password matches. $userPasswordHash = $user[$this->passwordColumnName]; if ($hashProvider->compareHash($password, $userPasswordHash)) { // Matching login - but is it enabled? if ($this->isModelActive($user)) { $this->LoggedIn = true; $this->LoggedInUserIdentifier = $user->getUniqueIdentifier(); $this->storeSession(); return true; } else { throw new LoginDisabledException(); } } throw new LoginFailedException(); }
function testXOR() { $filterOne = new \Rhubarb\Stem\Filters\Contains("Forename", "Jo", true); $filterTwo = new \Rhubarb\Stem\Filters\Contains("Surname", "Jo", true); $filterAnd = new \Rhubarb\Stem\Filters\Group("And"); $filterAnd->addFilters($filterOne, $filterTwo); $filterOr = new \Rhubarb\Stem\Filters\Group("Or"); $filterOr->addFilters($filterOne, $filterTwo); $filterNotAnd = new \Rhubarb\Stem\Filters\Not($filterAnd); $filterXor = new \Rhubarb\Stem\Filters\Group("And"); $filterXor->addFilters($filterNotAnd, $filterOr); $this->list->filter($filterXor); $this->assertCount(2, $this->list); $this->assertContains("Luc", $this->list[0]->Surname); }
public function testSum() { $examples = new Collection("Example"); list($sumTotal) = $examples->calculateAggregates([new Sum("CompanyID")]); $this->assertEquals(6, $sumTotal); }
public function testEmptyCandidatesArray() { $filter = new InArray("Surname", []); $this->list->filter($filter); $this->assertCount(0, $this->list); }
protected function getManualSortsRequiredForList(Collection $list) { $sorts = $list->getSorts(); $sorts = array_diff_key($sorts, array_flip($this->lastSortsUsed)); return $sorts; }
/** * Returns the Collection of models matching the given filter. * * @param Filter $filter * @return Collection */ public static function find(Filter $filter = null) { $modelClass = get_called_class(); $collections = new Collection($modelClass); if ($filter !== null) { $collections->filter($filter); } return $collections; }
public function fetchFor(Model $relatedTo) { $targetModel = SolutionSchema::getModel($this->targetModelName); $sourceValue = $relatedTo[$this->getSourceColumnName()]; $targetColumnName = $this->getTargetColumnName(); if ($targetColumnName == $targetModel->UniqueIdentifierColumnName) { if ($sourceValue === null) { return null; } try { return SolutionSchema::getModel($this->targetModelName, $sourceValue); } catch (RecordNotFoundException $er) { return null; } } else { $collection = new Collection($this->targetModelName); $collection->filter(new Equals($targetColumnName, $sourceValue)); if (sizeof($collection) > 0) { return $collection[0]; } } return null; }
/** * Returns the sorts needed for manual sorting. * * @param Collection $list * @return array */ protected function getManualSortsRequiredForList(Collection $list) { return $list->getSorts(); }
public function testLimits() { MySql::executeStatement("TRUNCATE TABLE tblCompany"); $company = new Company(); $repos = $company->getRepository(); $repos->clearObjectCache(); $company = new Company(); $company->CompanyName = "A"; $company->save(); $company = new Company(); $company->CompanyName = "B"; $company->save(); $company = new Company(); $company->CompanyName = "B"; $company->save(); $company = new Company(); $company->CompanyName = "B"; $company->save(); $company = new Company(); $company->CompanyName = "C"; $company->save(); $company = new Company(); $company->CompanyName = "D"; $company->save(); $list = new Collection("\\Rhubarb\\Stem\\Tests\\Fixtures\\Company"); $list->setRange(2, 6); $this->assertCount(6, $list); $this->assertEquals("C", $list[2]->CompanyName); $sql = MySql::getPreviousStatement(true); $this->assertContains("LIMIT 2, 6", $sql); // Sorting by a computed column should mean that limits are no longer used. $list->addSort("CompanyIDSquared", true); $this->assertCount(6, $list); $this->assertEquals("C", $list[2]->CompanyName); $sql = MySql::getPreviousStatement(); $this->assertNotContains("LIMIT 2, 6", $sql); $sql = MySql::getPreviousStatement(true); $this->assertNotContains("LIMIT 2, 6", $sql); }
/** * Get's the unique identifiers required for the matching filters and loads the data into * the cache for performance reasons. * * @param Collection $list * @param int $unfetchedRowCount * @param array $relationshipNavigationPropertiesToAutoHydrate * @return array */ public function getUniqueIdentifiersForDataList(Collection $list, &$unfetchedRowCount = 0, $relationshipNavigationPropertiesToAutoHydrate = []) { $this->lastSortsUsed = []; $schema = $this->schema; $table = $schema->schemaName; $whereClause = ""; $filter = $list->getFilter(); $namedParams = []; $propertiesToAutoHydrate = $relationshipNavigationPropertiesToAutoHydrate; $filteredExclusivelyByRepository = true; if ($filter !== null) { $filterSql = $filter->filterWithRepository($this, $namedParams, $propertiesToAutoHydrate); if ($filterSql != "") { $whereClause .= " WHERE " . $filterSql; } $filteredExclusivelyByRepository = $filter->wasFilteredByRepository(); } $relationships = SolutionSchema::getAllRelationshipsForModel($this->getModelClass()); $aggregateColumnClause = ""; $aggregateColumnClauses = []; $aggregateColumnAliases = []; $aggregateRelationshipPropertiesToAutoHydrate = []; foreach ($list->getAggregates() as $aggregate) { $clause = $aggregate->aggregateWithRepository($this, $aggregateRelationshipPropertiesToAutoHydrate); if ($clause != "") { $aggregateColumnClauses[] = $clause; $aggregateColumnAliases[] = $aggregate->getAlias(); } } if (sizeof($aggregateColumnClauses) > 0) { $aggregateColumnClause = ", " . implode(", ", $aggregateColumnClauses); } $aggregateRelationshipPropertiesToAutoHydrate = array_unique($aggregateRelationshipPropertiesToAutoHydrate); $joins = []; $groups = []; foreach ($aggregateRelationshipPropertiesToAutoHydrate as $joinRelationship) { /** * @var OneToMany $relationship */ $relationship = $relationships[$joinRelationship]; $targetModelName = $relationship->getTargetModelName(); $targetModelClass = SolutionSchema::getModelClass($targetModelName); /** * @var Model $targetModel */ $targetModel = new $targetModelClass(); $targetSchema = $targetModel->getSchema(); $joins[] = "LEFT JOIN `{$targetSchema->schemaName}` AS `{$joinRelationship}` ON `{$this->schema->schemaName}`.`" . $relationship->getSourceColumnName() . "` = `{$joinRelationship}`.`" . $relationship->getTargetColumnName() . "`"; $groups[] = "`{$table}`.`" . $relationship->getSourceColumnName() . '`'; } $joinColumns = []; $joinOriginalToAliasLookup = []; $joinColumnsByModel = []; $sorts = $list->getSorts(); $possibleSorts = []; $columns = $schema->getColumns(); foreach ($sorts as $columnName => $ascending) { if (!isset($columns[$columnName])) { // If this is a one to one relationship we can still sort by using auto hydration. $parts = explode(".", $columnName); $relationshipProperty = $parts[0]; $escapedColumnName = '`' . implode('`.`', $parts) . '`'; if (isset($relationships[$relationshipProperty]) && $relationships[$relationshipProperty] instanceof OneToOne) { $propertiesToAutoHydrate[] = $relationshipProperty; $possibleSorts[] = $escapedColumnName . " " . ($ascending ? "ASC" : "DESC"); $this->lastSortsUsed[] = $columnName; } else { // If the request sorts contain any that we can't sort by we must only sort by those // after this column. $possibleSorts = []; $this->lastSortsUsed = []; } } else { $possibleSorts[] = '`' . str_replace('.', '`.`', $columnName) . "` " . ($ascending ? "ASC" : "DESC"); $this->lastSortsUsed[] = $columnName; } } $propertiesToAutoHydrate = array_unique($propertiesToAutoHydrate); foreach ($propertiesToAutoHydrate as $joinRelationship) { /** * @var OneToMany $relationship */ $relationship = $relationships[$joinRelationship]; $targetModelName = $relationship->getTargetModelName(); $targetModelClass = SolutionSchema::getModelClass($targetModelName); /** * @var Model $targetModel */ $targetModel = new $targetModelClass(); $targetSchema = $targetModel->getSchema(); $columns = $targetSchema->getColumns(); foreach ($columns as $columnName => $column) { $joinColumns[$targetModelName . $columnName] = "`{$joinRelationship}`.`{$columnName}`"; $joinOriginalToAliasLookup[$targetModelName . "." . $columnName] = $targetModelName . $columnName; if (!isset($joinColumnsByModel[$targetModelName])) { $joinColumnsByModel[$targetModelName] = []; } $joinColumnsByModel[$targetModelName][$targetModelName . $columnName] = $columnName; } $joins[] = "LEFT JOIN `{$targetSchema->schemaName}` AS `{$joinRelationship}` ON `{$this->schema->schemaName}`.`" . $relationship->getSourceColumnName() . "` = `{$joinRelationship}`.`" . $relationship->getTargetColumnName() . "`"; } $joinString = ""; $joinColumnClause = ""; if (sizeof($joins)) { $joinString = " " . implode(" ", $joins); $joinClauses = []; foreach ($joinColumns as $aliasName => $columnName) { $joinClauses[] = "{$columnName} AS `{$aliasName}`"; } if (sizeof($joinClauses)) { $joinColumnClause = ", " . implode(", ", $joinClauses); } } $groupClause = ""; if (sizeof($groups)) { $groupClause = " GROUP BY " . implode(", ", $groups); } $orderBy = ""; if (sizeof($possibleSorts)) { $orderBy .= " ORDER BY " . implode(", ", $possibleSorts); } $sql = "SELECT `{$table}`.*{$joinColumnClause}{$aggregateColumnClause} FROM `{$table}`" . $joinString . $whereClause . $groupClause . $orderBy; $ranged = false; if ($filteredExclusivelyByRepository && sizeof($possibleSorts) == sizeof($sorts)) { $range = $list->getRange(); if ($range != false) { $ranged = true; $sql .= " LIMIT " . $range[0] . ", " . $range[1]; $sql = preg_replace("/^SELECT /", "SELECT SQL_CALC_FOUND_ROWS ", $sql); } } $statement = self::executeStatement($sql, $namedParams); $results = $statement->fetchAll(\PDO::FETCH_ASSOC); $uniqueIdentifiers = []; if (sizeof($joinColumns)) { foreach ($joinColumnsByModel as $joinModel => $modelJoinedColumns) { $model = SolutionSchema::getModel($joinModel); $repository = $model->getRepository(); foreach ($results as &$result) { $aliasedUniqueIdentifierColumnName = $joinOriginalToAliasLookup[$joinModel . "." . $model->UniqueIdentifierColumnName]; if (isset($result[$aliasedUniqueIdentifierColumnName]) && !isset($repository->cachedObjectData[$result[$aliasedUniqueIdentifierColumnName]])) { $joinedData = array_intersect_key($result, $modelJoinedColumns); $modelData = array_combine($modelJoinedColumns, $joinedData); $repository->cachedObjectData[$modelData[$model->UniqueIdentifierColumnName]] = $modelData; } $result = array_diff_key($result, $modelJoinedColumns); } unset($result); } } foreach ($results as $result) { $uniqueIdentifier = $result[$schema->uniqueIdentifierColumnName]; $result = $this->transformDataFromRepository($result); // Store the data in the cache and add the unique identifier to our list. $this->cachedObjectData[$uniqueIdentifier] = $result; $uniqueIdentifiers[] = $uniqueIdentifier; } if ($ranged) { $foundRows = Mysql::returnSingleValue("SELECT FOUND_ROWS()"); $unfetchedRowCount = $foundRows - sizeof($uniqueIdentifiers); } return $uniqueIdentifiers; }
public function testIsNullFilter() { MySql::executeStatement("TRUNCATE TABLE tblCompany"); $company = new \Rhubarb\Stem\Tests\Fixtures\Company(); $company->CompanyName = "GCD"; $company->save(); $companies = new Collection('Rhubarb\\Stem\\Tests\\Fixtures\\Company'); $companies->filter(new Equals("CompanyName", null)); $this->assertEquals(0, $companies->count()); $companies = new Collection('Rhubarb\\Stem\\Tests\\Fixtures\\Company'); $companies->filter(new Equals("ProjectCount", null)); $this->assertEquals(1, $companies->count()); }