Bolt\Legacy\Storage::decodeContentQuery PHP Method

decodeContentQuery() private method

This is tightly coupled to $this->getContent()
private decodeContentQuery ( string $textquery, array $inParameters = null ) : array
$textquery string
$inParameters array
return array decoded query, keys: contenttypes - array, contenttypeslugs that will be returned return_single - boolean, true if only 1 result should be returned self_paginated - boolean, true if already be paginated order_callback - callback, sort results post-hydration after everything is merged queries - array of SQL query parts: * tablename - tablename * contenttype - contenttype array * from - from part * where - where part * order - order part * params - bind-parameters parameters - parameters to use after the queries
    private function decodeContentQuery($textquery, $inParameters = null)
    {
        $decoded = ['contenttypes' => [], 'return_single' => false, 'self_paginated' => true, 'order_callback' => false, 'queries' => [], 'parameters' => [], 'hydrate' => true];
        list($metaParameters, $ctypeParameters) = $this->organizeQueryParameters($inParameters);
        $this->parseTextQuery($textquery, $decoded, $metaParameters, $ctypeParameters);
        // $decoded['contettypes'] gotten here
        // get page nr. from url if has
        $metaParameters['page'] = $this->app['pager']->getCurrentPage(implode('_', $decoded['contenttypes']));
        $this->prepareDecodedQueryForUse($decoded, $metaParameters, $ctypeParameters);
        $decoded['parameters'] = $metaParameters;
        // for all the non-reserved parameters that are fields or taxonomies, we assume people want to do a 'where'
        foreach ($ctypeParameters as $contenttypeslug => $actualParameters) {
            $contenttype = $this->getContentType($contenttypeslug);
            $tablename = $this->getContenttypeTablename($contenttype);
            $where = [];
            $order = [];
            // Set the 'order', if specified in the meta_parameters.
            if (!empty($metaParameters['order'])) {
                $order[] = $this->getEscapedSortorder($metaParameters['order'], false);
            }
            $query = ['tablename' => $tablename, 'contenttype' => $contenttype, 'from' => sprintf('FROM %s', $tablename), 'where' => '', 'order' => '', 'params' => []];
            if ($contenttype === false) {
                /*
                 * We were logging here, but a couple of places like
                 * TwigExtension::menuHelper() would trigger lots of hits,
                 * filling logs and impacting performance as a result.
                 * @see #1799 https://github.com/bolt/bolt/issues/1799
                 *
                 * When we refactor we need to address the callers, as this is a
                 * valid error state.
                 */
                continue;
            }
            if (is_array($actualParameters)) {
                // Set the 'FROM' part of the query, without the LEFT JOIN (i.e. no taxonomies..)
                foreach ($actualParameters as $key => $value) {
                    if ($key == 'order') {
                        $orderValue = $this->decodeQueryOrder($contenttype, $value);
                        if ($orderValue !== false) {
                            $order[] = $orderValue;
                        }
                        continue;
                    }
                    if ($key == 'filter' && !empty($value)) {
                        $filterWhere = [];
                        foreach ($contenttype['fields'] as $name => $fieldconfig) {
                            if (in_array($fieldconfig['type'], ['text', 'textarea', 'html', 'markdown'])) {
                                $filterWhere[] = sprintf('%s.%s LIKE %s', $tablename, $name, $this->app['db']->quote('%' . $value . '%'));
                            }
                        }
                        if (count($filterWhere) > 0) {
                            $where[] = '(' . implode(' OR ', $filterWhere) . ')';
                        }
                        continue;
                    }
                    // build OR parts if key contains "|||"
                    if (strpos($key, " ||| ") !== false) {
                        $keyParts = explode(" ||| ", $key);
                        $valParts = explode(" ||| ", $value);
                        $orPart = '( ';
                        $countParts = count($keyParts);
                        for ($i = 0; $i < $countParts; $i++) {
                            if (in_array($keyParts[$i], $this->getContentTypeFields($contenttype['slug'])) || in_array($keyParts[$i], Content::getBaseColumns())) {
                                $rkey = $tablename . '.' . $keyParts[$i];
                                $fieldtype = $this->getContentTypeFieldType($contenttype['slug'], $keyParts[$i]);
                                $orPart .= ' (' . $this->parseWhereParameter($rkey, $valParts[$i], $fieldtype) . ') OR ';
                            }
                        }
                        if (strlen($orPart) > 2) {
                            $where[] = substr($orPart, 0, -4) . ') ';
                        }
                    }
                    // for all the parameters that are fields
                    if (in_array($key, $this->getContentTypeFields($contenttype['slug'])) || in_array($key, Content::getBaseColumns())) {
                        $rkey = $tablename . '.' . $key;
                        $fieldtype = $this->getContentTypeFieldType($contenttype['slug'], $key);
                        $where[] = $this->parseWhereParameter($rkey, $value, $fieldtype);
                    }
                    // for all the parameters that are taxonomies
                    if (array_key_exists($key, $this->getContentTypeTaxonomy($contenttype['slug']))) {
                        // check if we're trying to use "!" as a way of 'not'. If so, we need to do a 'NOT IN', instead
                        // of 'IN'. And, the parameter in the subselect needs to be without "!" as a consequence.
                        if (strpos($value, "!") !== false) {
                            $notin = "NOT ";
                            $value = str_replace("!", "", $value);
                        } else {
                            $notin = "";
                        }
                        // Set the extra '$where', with subselect for taxonomies.
                        $where[] = sprintf('%s %s IN (SELECT content_id AS id FROM %s where %s AND ( %s OR %s ) AND %s)', $this->app['db']->quoteIdentifier('id'), $notin, $this->getTablename('taxonomy'), $this->parseWhereParameter($this->getTablename('taxonomy') . '.taxonomytype', $key), $this->parseWhereParameter($this->getTablename('taxonomy') . '.slug', $value), $this->parseWhereParameter($this->getTablename('taxonomy') . '.name', $value), $this->parseWhereParameter($this->getTablename('taxonomy') . '.contenttype', $contenttype['slug']));
                    }
                }
            }
            if (count($order) == 0) {
                $order[] = $this->decodeQueryOrder($contenttype, false) ?: 'datepublish DESC';
            }
            if (count($where) > 0) {
                $query['where'] = sprintf('WHERE (%s)', implode(' AND ', $where));
            }
            if (count($order) > 0) {
                $order = implode(', ', $order);
                if (!empty($order)) {
                    $query['order'] = sprintf('ORDER BY %s', $order);
                }
            }
            $decoded['queries'][] = $query;
            if (isset($inParameters['hydrate'])) {
                $decoded['hydrate'] = $inParameters['hydrate'];
            }
        }
        return $decoded;
    }