Example #1
0
 /**
  * Constructor
  *
  * @param EntityCache $entity_cache Entity cache
  * @param EntityTable $entity_table Entity service
  */
 public function __construct(EntityCache $entity_cache, EntityTable $entity_table)
 {
     $this->_callable_cache_checker = function ($guid) use($entity_cache) {
         return $entity_cache->get($guid);
     };
     $this->_callable_entity_loader = function ($options) use($entity_table) {
         return $entity_table->getEntities($options);
     };
 }
Example #2
0
 /**
  * Sets the last logon time of the given user to right now.
  *
  * @param ElggUser $user User entity
  * @return void
  */
 public function setLastLogin(ElggUser $user)
 {
     $time = $this->getCurrentTime()->getTimestamp();
     if ($user->last_login == $time) {
         // no change required
         return;
     }
     $query = "\n\t\t\tUPDATE {$this->table}\n\t\t\tSET\n\t\t\t\tprev_last_login = last_login,\n\t\t\t\tlast_login = :last_login\n\t\t\tWHERE guid = :guid\n\t\t";
     $params = [':last_login' => $time, ':guid' => (int) $user->guid];
     $user->prev_last_login = $user->last_login;
     $user->last_login = $time;
     execute_delayed_write_query($query, null, $params);
     $this->entity_cache->set($user);
     // If we save the user to memcache during this request, then we'll end up with the
     // old (incorrect) attributes cached. Hence we want to invalidate as late as possible.
     // the user object gets saved
     register_shutdown_function(function () use($user) {
         $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache'));
     });
 }
Example #3
0
 /**
  * Return entities from an SQL query generated by elgg_get_entities.
  *
  * @access private
  *
  * @param string    $sql
  * @param ElggBatch $batch
  * @return ElggEntity[]
  * @throws LogicException
  */
 public function fetchFromSql($sql, \ElggBatch $batch = null)
 {
     $plugin_subtype = $this->subtype_table->getId('object', 'plugin');
     // Keys are types, values are columns that, if present, suggest that the secondary
     // table is already JOINed. Note it's OK if guess incorrectly because entity load()
     // will fetch any missing attributes.
     $types_to_optimize = array('object' => 'title', 'user' => 'password_hash', 'group' => 'name', 'site' => 'url');
     $rows = $this->db->getData($sql);
     // guids to look up in each type
     $lookup_types = array();
     // maps GUIDs to the $rows key
     $guid_to_key = array();
     if (isset($rows[0]->type, $rows[0]->subtype) && $rows[0]->type === 'object' && $rows[0]->subtype == $plugin_subtype) {
         // Likely the entire resultset is plugins, which have already been optimized
         // to JOIN the secondary table. In this case we allow retrieving from cache,
         // but abandon the extra queries.
         $types_to_optimize = array();
     }
     // First pass: use cache where possible, gather GUIDs that we're optimizing
     foreach ($rows as $i => $row) {
         if (empty($row->guid) || empty($row->type)) {
             throw new LogicException('Entity row missing guid or type');
         }
         // We try ephemeral cache because it's blazingly fast and we ideally want to access
         // the same PHP instance. We don't try memcache because it isn't worth the overhead.
         $entity = $this->entity_cache->get($row->guid);
         if ($entity) {
             // from static var, must be refreshed in case row has extra columns
             $entity->refresh($row);
             $rows[$i] = $entity;
             continue;
         }
         if (isset($types_to_optimize[$row->type])) {
             // check if row already looks JOINed.
             if (isset($row->{$types_to_optimize[$row->type]})) {
                 // Row probably already contains JOINed secondary table. Don't make another query just
                 // to pull data that's already there
                 continue;
             }
             $lookup_types[$row->type][] = $row->guid;
             $guid_to_key[$row->guid] = $i;
         }
     }
     // Do secondary queries and merge rows
     if ($lookup_types) {
         foreach ($lookup_types as $type => $guids) {
             $set = "(" . implode(',', $guids) . ")";
             $sql = "SELECT * FROM {$this->db->prefix}{$type}s_entity WHERE guid IN {$set}";
             $secondary_rows = $this->db->getData($sql);
             if ($secondary_rows) {
                 foreach ($secondary_rows as $secondary_row) {
                     $key = $guid_to_key[$secondary_row->guid];
                     // cast to arrays to merge then cast back
                     $rows[$key] = (object) array_merge((array) $rows[$key], (array) $secondary_row);
                 }
             }
         }
     }
     // Second pass to finish conversion
     foreach ($rows as $i => $row) {
         if ($row instanceof ElggEntity) {
             continue;
         } else {
             try {
                 $rows[$i] = $this->rowToElggStar($row);
             } catch (IncompleteEntityException $e) {
                 // don't let incomplete entities throw fatal errors
                 unset($rows[$i]);
                 // report incompletes to the batch process that spawned this query
                 if ($batch) {
                     $batch->reportIncompleteEntity($row);
                 }
             }
         }
     }
     return $rows;
 }