/**
  * Checks if additional select columns are readable as volatile data even if we hit the cache while fetching entity.
  *
  * https://github.com/Elgg/Elgg/issues/5544
  */
 public function testSqlAdditionalSelectsAsVolatileDataWithCache()
 {
     // remove ignore access as it disables entity cache
     $access = elgg_set_ignore_access(false);
     // may not have groups in DB - let's create one
     $group = new ElggGroup();
     $group->name = 'test_group';
     $group->access_id = ACCESS_PUBLIC;
     $this->assertTrue($group->save() !== false);
     foreach (array('site', 'user', 'group', 'object') as $type) {
         $entities = elgg_get_entities(array('type' => $type, 'selects' => array('42 as added_col3'), 'limit' => 1));
         $entity = array_shift($entities);
         $this->assertTrue($entity instanceof ElggEntity);
         $this->assertEqual($entity->added_col3, null, "Additional select columns are leaking to attributes for " . get_class($entity));
         $this->assertEqual($entity->getVolatileData('select:added_col3'), 42);
         // make sure we have cached the entity
         $this->assertNotEqual(false, _elgg_retrieve_cached_entity($entity->guid));
     }
     // run these again but with different value to make sure cache does not interfere
     foreach (array('site', 'user', 'group', 'object') as $type) {
         $entities = elgg_get_entities(array('type' => $type, 'selects' => array('64 as added_col3'), 'limit' => 1));
         $entity = array_shift($entities);
         $this->assertTrue($entity instanceof ElggEntity);
         $this->assertEqual($entity->added_col3, null, "Additional select columns are leaking to attributes for " . get_class($entity));
         $this->assertEqual($entity->getVolatileData('select:added_col3'), 64, "Failed to overwrite volatile data in cached entity");
     }
     elgg_set_ignore_access($access);
     $group->delete();
 }
Esempio n. 2
0
/**
 * Retrieve a entity from the cache.
 *
 * @param int $guid The guid
 *
 * @return ElggEntity|bool false if entity not cached, or not fully loaded
 * @access private
 * @deprecated 1.8
 */
function retrieve_cached_entity($guid)
{
    elgg_deprecated_notice('retrieve_cached_entity() is a private function and should not be used.', 1.8);
    return _elgg_retrieve_cached_entity($guid);
}
Esempio n. 3
0
 /**
  * Get entities in any order checking cache first
  *
  * @param int[] $guids
  * @return \ElggEntity[]
  */
 protected function getEntities(array $guids)
 {
     // most objects are already preloaded
     $entities = array();
     $fetch_guids = array();
     foreach ($guids as $guid) {
         $entity = _elgg_retrieve_cached_entity($guid);
         if ($entity) {
             $entities[] = $entity;
         } else {
             $fetch_guids[] = $guid;
         }
     }
     if ($fetch_guids) {
         $fetched = elgg_get_entities(array('guids' => $fetch_guids));
         array_splice($entities, count($entities), 0, $fetched);
     }
     return $entities;
 }
Esempio n. 4
0
/**
 * Prefetch entities that will be displayed in the river.
 *
 * @param \ElggRiverItem[] $river_items
 * @access private
 */
function _elgg_prefetch_river_entities(array $river_items)
{
    // prefetch objects, subjects and targets
    $guids = array();
    foreach ($river_items as $item) {
        if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) {
            $guids[$item->subject_guid] = true;
        }
        if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) {
            $guids[$item->object_guid] = true;
        }
        if ($item->target_guid && !_elgg_retrieve_cached_entity($item->target_guid)) {
            $guids[$item->target_guid] = true;
        }
    }
    if ($guids) {
        // The entity cache only holds 256. We don't want to bump out any plugins.
        $guids = array_slice($guids, 0, 200, true);
        // return value unneeded, just priming cache
        elgg_get_entities(array('guids' => array_keys($guids), 'limit' => 0, 'distinct' => false));
    }
    // prefetch object containers, in case they were not in the targets
    $guids = array();
    foreach ($river_items as $item) {
        $object = $item->getObjectEntity();
        if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) {
            $guids[$object->container_guid] = true;
        }
    }
    if ($guids) {
        $guids = array_slice($guids, 0, 200, true);
        elgg_get_entities(array('guids' => array_keys($guids), 'limit' => 0, 'distinct' => false, 'type' => 'group'));
    }
    // Note: We've tried combining the above ege() calls into one (pulling containers at the same time).
    // Although it seems like it would reduce queries, it added some. o_O
}
Esempio n. 5
0
 /**
  * Return entities from an SQL query generated by elgg_get_entities.
  *
  * @param string    $sql
  * @param \ElggBatch $batch
  * @return \ElggEntity[]
  *
  * @access private
  * @throws \LogicException
  */
 function fetchFromSql($sql, \ElggBatch $batch = null)
 {
     static $plugin_subtype;
     if (null === $plugin_subtype) {
         $plugin_subtype = get_subtype_id('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', 'group' => 'name', 'site' => 'url');
     $rows = _elgg_services()->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');
         }
         $entity = _elgg_retrieve_cached_entity($row->guid);
         if ($entity) {
             $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) {
         $dbprefix = _elgg_services()->config->get('dbprefix');
         foreach ($lookup_types as $type => $guids) {
             $set = "(" . implode(',', $guids) . ")";
             $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN {$set}";
             $secondary_rows = _elgg_services()->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] = entity_row_to_elggstar($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;
 }
Esempio n. 6
0
/**
 * Prefetch entities that will be displayed in the river.
 *
 * @param ElggRiverItem[] $river_items
 * @access private
 */
function _elgg_prefetch_river_entities(array $river_items)
{
    // prefetch objects and subjects
    $guids = array();
    foreach ($river_items as $item) {
        if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) {
            $guids[$item->subject_guid] = true;
        }
        if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) {
            $guids[$item->object_guid] = true;
        }
    }
    if ($guids) {
        // avoid creating oversized query
        // @todo how to better handle this?
        $guids = array_slice($guids, 0, 300, true);
        // return value unneeded, just priming cache
        elgg_get_entities(array('guids' => array_keys($guids), 'limit' => 0));
    }
    // prefetch object containers
    $guids = array();
    foreach ($river_items as $item) {
        $object = $item->getObjectEntity();
        if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) {
            $guids[$object->container_guid] = true;
        }
    }
    if ($guids) {
        $guids = array_slice($guids, 0, 300, true);
        elgg_get_entities(array('guids' => array_keys($guids), 'limit' => 0));
    }
}
Esempio n. 7
0
 /**
  * Get user by username
  *
  * @param string $username The user's username
  *
  * @return \ElggUser|false Depending on success
  */
 function getByUsername($username)
 {
     global $USERNAME_TO_GUID_MAP_CACHE;
     // Fixes #6052. Username is frequently sniffed from the path info, which,
     // unlike $_GET, is not URL decoded. If the username was not URL encoded,
     // this is harmless.
     $username = rawurldecode($username);
     $username = sanitise_string($username);
     $access = _elgg_get_access_where_sql();
     // Caching
     if (isset($USERNAME_TO_GUID_MAP_CACHE[$username]) && _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username])) {
         return _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
     }
     $query = "SELECT e.* FROM {$this->CONFIG->dbprefix}users_entity u\n\t\t\tJOIN {$this->CONFIG->dbprefix}entities e ON e.guid = u.guid\n\t\t\tWHERE u.username = '******' AND {$access}";
     $entity = _elgg_services()->db->getDataRow($query, 'entity_row_to_elggstar');
     if ($entity) {
         $USERNAME_TO_GUID_MAP_CACHE[$username] = $entity->guid;
     } else {
         $entity = false;
     }
     return $entity;
 }
Esempio n. 8
0
/**
 * Get user by session code
 *
 * @param string $code The session code
 *
 * @return ElggUser|false Depending on success
 */
function get_user_by_code($code)
{
    global $CONFIG, $CODE_TO_GUID_MAP_CACHE;
    $code = sanitise_string($code);
    $access = get_access_sql_suffix('e');
    // Caching
    if (isset($CODE_TO_GUID_MAP_CACHE[$code]) && _elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code])) {
        return _elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]);
    }
    $query = "SELECT e.* from {$CONFIG->dbprefix}users_entity u\n\t\tjoin {$CONFIG->dbprefix}entities e on e.guid=u.guid\n\t\twhere u.code='{$code}' and {$access}";
    $entity = get_data_row($query, 'entity_row_to_elggstar');
    if ($entity) {
        $CODE_TO_GUID_MAP_CACHE[$code] = $entity->guid;
    }
    return $entity;
}
Esempio n. 9
0
/**
 * Get user by username
 *
 * @param string $username The user's username
 *
 * @return ElggUser|false Depending on success
 */
function get_user_by_username($username)
{
    global $CONFIG, $USERNAME_TO_GUID_MAP_CACHE;
    $username = sanitise_string($username);
    $access = _elgg_get_access_where_sql();
    // Caching
    if (isset($USERNAME_TO_GUID_MAP_CACHE[$username]) && _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username])) {
        return _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
    }
    $query = "SELECT e.* FROM {$CONFIG->dbprefix}users_entity u\n\t\tJOIN {$CONFIG->dbprefix}entities e ON e.guid = u.guid\n\t\tWHERE u.username = '******' AND {$access}";
    $entity = get_data_row($query, 'entity_row_to_elggstar');
    if ($entity) {
        $USERNAME_TO_GUID_MAP_CACHE[$username] = $entity->guid;
    } else {
        $entity = false;
    }
    return $entity;
}