Elgg\Database\EntityTable::fetchFromSql PHP Method

fetchFromSql() public method

Return entities from an SQL query generated by elgg_get_entities.
public fetchFromSql ( string $sql, ElggBatch $batch = null ) : ElggEntit\ElggEntity[]
$sql string
$batch ElggBatch
return ElggEntit\ElggEntity[]
    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;
    }