MDL-64057 core_favourites: add get_join_sql_by_type() to service layer

This provides a way for external queries to include information about
favourited items.
This commit is contained in:
Jake Dallimore
2018-11-23 11:02:18 +08:00
parent 0225ad42ea
commit 92bea7db2a
2 changed files with 77 additions and 1 deletions
@@ -110,6 +110,51 @@ class user_favourite_service {
);
}
/**
* Returns the SQL required to include favourite information for a given component/itemtype combination.
*
* Generally, find_favourites_by_type() is the recommended way to fetch favourites.
*
* This method is used to include favourite information in external queries, for items identified by their
* component and itemtype, matching itemid to the $joinitemid, and for the user to which this service is scoped.
*
* It uses a LEFT JOIN to preserve the original records. If you wish to restrict your records, please consider using a
* "WHERE {$tablealias}.id IS NOT NULL" in your query.
*
* Example usage:
*
* list($sql, $params) = $service->get_join_sql_by_type('core_message', 'message_conversations', 'myfavouritetablealias',
* 'conv.id');
* Results in $sql:
* "LEFT JOIN {favourite} fav
* ON fav.component = :favouritecomponent
* AND fav.itemtype = :favouriteitemtype
* AND fav.userid = 1234
* AND fav.itemid = conv.id"
* and $params:
* ['favouritecomponent' => 'core_message', 'favouriteitemtype' => 'message_conversations']
*
* @param string $component the frankenstyle component name.
* @param string $itemtype the type of the favourited item.
* @param string $tablealias the desired alias for the favourites table.
* @param string $joinitemid the table and column identifier which the itemid is joined to. E.g. conversation.id.
* @return array the list of sql and params, in the format [$sql, $params].
*/
public function get_join_sql_by_type(string $component, string $itemtype, string $tablealias, string $joinitemid) : array {
$sql = " LEFT JOIN {favourite} {$tablealias}
ON {$tablealias}.component = :favouritecomponent
AND {$tablealias}.itemtype = :favouriteitemtype
AND {$tablealias}.userid = {$this->userid}
AND {$tablealias}.itemid = {$joinitemid} ";
$params = [
'favouritecomponent' => $component,
'favouriteitemtype' => $itemtype,
];
return [$sql, $params];
}
/**
* Delete a favourite item from an area and from within a context.
*
@@ -186,7 +231,7 @@ class user_favourite_service {
* @param string $component the frankenstyle component name.
* @param string $itemtype the type of the favourited item.
* @param \context|null $context the context of the item which was favourited.
* @return favourite|null
* @return int
*/
public function count_favourites_by_type(string $component, string $itemtype, \context $context = null) {
$criteria = [
+31
View File
@@ -429,4 +429,35 @@ class user_favourite_service_testcase extends advanced_testcase {
// Gets counted if we include all contexts.
$this->assertEquals(3, $service->count_favourites_by_type('core_course', 'course'));
}
/**
* Verify that the join sql generated by get_join_sql_by_type is valid and can be used to include favourite information.
*/
public function test_get_join_sql_by_type() {
global $DB;
list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
// Get a user_favourite_service for the user.
// We need to use a real (DB) repository, as we want to run the SQL.
$repo = new \core_favourites\local\repository\favourite_repository();
$service = new \core_favourites\local\service\user_favourite_service($user1context, $repo);
// Favourite the first course only.
$service->create_favourite('core_course', 'course', $course1context->instanceid, $course1context);
// Generate the join snippet.
list($favsql, $favparams) = $service->get_join_sql_by_type('core_course', 'course', 'favalias', 'c.id');
// Join against a simple select, including the 2 courses only.
$params = ['courseid1' => $course1context->instanceid, 'courseid2' => $course2context->instanceid];
$params = $params + $favparams;
$records = $DB->get_records_sql("SELECT c.id, favalias.component
FROM {course} c $favsql
WHERE c.id = :courseid1 OR c.id = :courseid2", $params);
// Verify the favourite information is returned, but only for the favourited course.
$this->assertCount(2, $records);
$this->assertEquals('core_course', $records[$course1context->instanceid]->component);
$this->assertEmpty($records[$course2context->instanceid]->component);
}
}