Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  /**
  17   * Contains the favourite_repository class, responsible for CRUD operations for favourites.
  18   *
  19   * @package   core_favourites
  20   * @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  namespace core_favourites\local\repository;
  24  use \core_favourites\local\entity\favourite;
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Class favourite_repository.
  30   *
  31   * This class handles persistence of favourites. Favourites from all areas are supported by this repository.
  32   *
  33   * @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
  34   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class favourite_repository implements favourite_repository_interface {
  37  
  38      /**
  39       * @var string the name of the table which favourites are stored in.
  40       */
  41      protected $favouritetable = 'favourite';
  42  
  43      /**
  44       * Get a favourite object, based on a full record.
  45       * @param \stdClass $record the record we wish to hydrate.
  46       * @return favourite the favourite record.
  47       */
  48      protected function get_favourite_from_record(\stdClass $record) : favourite {
  49          $favourite = new favourite(
  50              $record->component,
  51              $record->itemtype,
  52              $record->itemid,
  53              $record->contextid,
  54              $record->userid
  55          );
  56          $favourite->id = $record->id;
  57          $favourite->ordering = $record->ordering ?? null;
  58          $favourite->timecreated = $record->timecreated ?? null;
  59          $favourite->timemodified = $record->timemodified ?? null;
  60  
  61          return $favourite;
  62      }
  63  
  64      /**
  65       * Get a list of favourite objects, based on a list of records.
  66       * @param array $records the record we wish to hydrate.
  67       * @return array the list of favourites.
  68       */
  69      protected function get_list_of_favourites_from_records(array $records) {
  70          $list = [];
  71          foreach ($records as $index => $record) {
  72              $list[$index] = $this->get_favourite_from_record($record);
  73          }
  74          return $list;
  75      }
  76  
  77      /**
  78       * Basic validation, confirming we have the minimum field set needed to save a record to the store.
  79       *
  80       * @param favourite $favourite the favourite record to validate.
  81       * @throws \moodle_exception if the supplied favourite has missing or unsupported fields.
  82       */
  83      protected function validate(favourite $favourite) {
  84  
  85          $favourite = (array)$favourite;
  86  
  87          // The allowed fields, and whether or not each is required to create a record.
  88          // The timecreated, timemodified and id fields are generated during create/update.
  89          $allowedfields = [
  90              'userid' => true,
  91              'component' => true,
  92              'itemtype' => true,
  93              'itemid' => true,
  94              'contextid' => true,
  95              'ordering' => false,
  96              'timecreated' => false,
  97              'timemodified' => false,
  98              'id' => false
  99          ];
 100  
 101          $requiredfields = array_filter($allowedfields, function($field) {
 102              return $field;
 103          });
 104  
 105          if ($missingfields = array_keys(array_diff_key($requiredfields, $favourite))) {
 106              throw new \moodle_exception("Missing object property(s) '" . join(', ', $missingfields) . "'.");
 107          }
 108  
 109          // If the record contains fields we don't allow, throw an exception.
 110          if ($unsupportedfields = array_keys(array_diff_key($favourite, $allowedfields))) {
 111              throw new \moodle_exception("Unexpected object property(s) '" . join(', ', $unsupportedfields) . "'.");
 112          }
 113      }
 114  
 115      /**
 116       * Add a favourite to the repository.
 117       *
 118       * @param favourite $favourite the favourite to add.
 119       * @return favourite the favourite which has been stored.
 120       * @throws \dml_exception if any database errors are encountered.
 121       * @throws \moodle_exception if the favourite has missing or invalid properties.
 122       */
 123      public function add(favourite $favourite) : favourite {
 124          global $DB;
 125          $this->validate($favourite);
 126          $favourite = (array)$favourite;
 127          $time = time();
 128          $favourite['timecreated'] = $time;
 129          $favourite['timemodified'] = $time;
 130          $id = $DB->insert_record($this->favouritetable, $favourite);
 131          return $this->find($id);
 132      }
 133  
 134      /**
 135       * Add a collection of favourites to the repository.
 136       *
 137       * @param array $items the list of favourites to add.
 138       * @return array the list of favourites which have been stored.
 139       * @throws \dml_exception if any database errors are encountered.
 140       * @throws \moodle_exception if any of the favourites have missing or invalid properties.
 141       */
 142      public function add_all(array $items) : array {
 143          global $DB;
 144          $time = time();
 145          foreach ($items as $item) {
 146              $this->validate($item);
 147              $favourite = (array)$item;
 148              $favourite['timecreated'] = $time;
 149              $favourite['timemodified'] = $time;
 150              $ids[] = $DB->insert_record($this->favouritetable, $favourite);
 151          }
 152          list($insql, $params) = $DB->get_in_or_equal($ids);
 153          $records = $DB->get_records_select($this->favouritetable, "id $insql", $params);
 154          return $this->get_list_of_favourites_from_records($records);
 155      }
 156  
 157      /**
 158       * Find a favourite by id.
 159       *
 160       * @param int $id the id of the favourite.
 161       * @return favourite the favourite.
 162       * @throws \dml_exception if any database errors are encountered.
 163       */
 164      public function find(int $id) : favourite {
 165          global $DB;
 166          $record = $DB->get_record($this->favouritetable, ['id' => $id], '*', MUST_EXIST);
 167          return $this->get_favourite_from_record($record);
 168      }
 169  
 170      /**
 171       * Return all items in this repository, as an array, indexed by id.
 172       *
 173       * @param int $limitfrom optional pagination control for returning a subset of records, starting at this point.
 174       * @param int $limitnum optional pagination control for returning a subset comprising this many records.
 175       * @return array the list of all favourites stored within this repository.
 176       * @throws \dml_exception if any database errors are encountered.
 177       */
 178      public function find_all(int $limitfrom = 0, int $limitnum = 0) : array {
 179          global $DB;
 180          $records = $DB->get_records($this->favouritetable, null, '', '*', $limitfrom, $limitnum);
 181          return $this->get_list_of_favourites_from_records($records);
 182      }
 183  
 184      /**
 185       * Return all items matching the supplied criteria (a [key => value,..] list).
 186       *
 187       * @param array $criteria the list of key/value(s) criteria pairs.
 188       * @param int $limitfrom optional pagination control for returning a subset of records, starting at this point.
 189       * @param int $limitnum optional pagination control for returning a subset comprising this many records.
 190       * @return array the list of favourites matching the criteria.
 191       * @throws \dml_exception if any database errors are encountered.
 192       */
 193      public function find_by(array $criteria, int $limitfrom = 0, int $limitnum = 0) : array {
 194          global $DB;
 195          $conditions = [];
 196          $params = [];
 197          foreach ($criteria as $field => $value) {
 198              if (is_array($value) && count($value)) {
 199                  list($insql, $inparams) = $DB->get_in_or_equal($value, SQL_PARAMS_NAMED);
 200                  $conditions[] = "$field $insql";
 201                  $params = array_merge($params, $inparams);
 202              } else {
 203                  $conditions[] = "$field = :$field";
 204                  $params = array_merge($params, [$field => $value]);
 205              }
 206          }
 207  
 208          $records = $DB->get_records_select($this->favouritetable, implode(' AND ', $conditions), $params,
 209              '', '*', $limitfrom, $limitnum);
 210  
 211          return $this->get_list_of_favourites_from_records($records);
 212      }
 213  
 214      /**
 215       * Find a specific favourite, based on the properties known to identify it.
 216       *
 217       * Used if we don't know its id.
 218       *
 219       * @param int $userid the id of the user to which the favourite belongs.
 220       * @param string $component the frankenstyle component name.
 221       * @param string $itemtype the type of the favourited item.
 222       * @param int $itemid the id of the item which was favourited (not the favourite's id).
 223       * @param int $contextid the contextid of the item which was favourited.
 224       * @return favourite the favourite.
 225       * @throws \dml_exception if any database errors are encountered or if the record could not be found.
 226       */
 227      public function find_favourite(int $userid, string $component, string $itemtype, int $itemid, int $contextid) : favourite {
 228          global $DB;
 229          // Favourites model: We know that only one favourite can exist based on these properties.
 230          $record = $DB->get_record($this->favouritetable, [
 231              'userid' => $userid,
 232              'component' => $component,
 233              'itemtype' => $itemtype,
 234              'itemid' => $itemid,
 235              'contextid' => $contextid
 236          ], '*', MUST_EXIST);
 237          return $this->get_favourite_from_record($record);
 238      }
 239  
 240      /**
 241       * Check whether a favourite exists in this repository, based on its id.
 242       *
 243       * @param int $id the id to search for.
 244       * @return bool true if the favourite exists, false otherwise.
 245       * @throws \dml_exception if any database errors are encountered.
 246       */
 247      public function exists(int $id) : bool {
 248          global $DB;
 249          return $DB->record_exists($this->favouritetable, ['id' => $id]);
 250      }
 251  
 252      /**
 253       * Check whether an item exists in this repository, based on the specified criteria.
 254       *
 255       * @param array $criteria the list of key/value criteria pairs.
 256       * @return bool true if the favourite exists, false otherwise.
 257       * @throws \dml_exception if any database errors are encountered.
 258       */
 259      public function exists_by(array $criteria) : bool {
 260          global $DB;
 261          return $DB->record_exists($this->favouritetable, $criteria);
 262      }
 263  
 264      /**
 265       * Update a favourite.
 266       *
 267       * @param favourite $favourite the favourite to update.
 268       * @return favourite the updated favourite.
 269       * @throws \dml_exception if any database errors are encountered.
 270       */
 271      public function update(favourite $favourite) : favourite {
 272          global $DB;
 273          $time = time();
 274          $favourite->timemodified = $time;
 275          $DB->update_record($this->favouritetable, $favourite);
 276          return $this->find($favourite->id);
 277      }
 278  
 279      /**
 280       * Delete a favourite, by id.
 281       *
 282       * @param int $id the id of the favourite to delete.
 283       * @throws \dml_exception if any database errors are encountered.
 284       */
 285      public function delete(int $id) {
 286          global $DB;
 287          $DB->delete_records($this->favouritetable, ['id' => $id]);
 288      }
 289  
 290      /**
 291       * Delete all favourites matching the specified criteria.
 292       *
 293       * @param array $criteria the list of key/value criteria pairs.
 294       * @throws \dml_exception if any database errors are encountered.
 295       */
 296      public function delete_by(array $criteria) {
 297          global $DB;
 298          $DB->delete_records($this->favouritetable, $criteria);
 299      }
 300  
 301      /**
 302       * Return the total number of favourites in this repository.
 303       *
 304       * @return int the total number of items.
 305       * @throws \dml_exception if any database errors are encountered.
 306       */
 307      public function count() : int {
 308          global $DB;
 309          return $DB->count_records($this->favouritetable);
 310      }
 311  
 312      /**
 313       * Return the number of user favourites matching the specified criteria.
 314       *
 315       * @param array $criteria the list of key/value criteria pairs.
 316       * @return int the number of favourites matching the criteria.
 317       * @throws \dml_exception if any database errors are encountered.
 318       */
 319      public function count_by(array $criteria) : int {
 320          global $DB;
 321          return $DB->count_records($this->favouritetable, $criteria);
 322      }
 323  }