private function loadLinks() { if ($this->linksLoaded) { return; } // TODO: in new Bolt version use getContenttypeTablename instead of getTablename. $tableStructures = $this->app['storage']->getTablename('structures'); $structures = $this->app['db']->fetchAll("SELECT id FROM {$tableStructures} WHERE status = 'published'"); $availableStructures = util::array_pluck($structures, 'id'); $contenttypes = $this->app['config']->get('contenttypes'); foreach ($contenttypes as $contenttype) { if (isset($contenttype['fields']['structure_parent'])) { $contenttypeslug = $contenttype['slug']; $tablename = $this->app['storage']->getTablename($contenttypeslug); $stmt = $this->app['db']->prepare("SELECT id, structure_parent FROM {$tablename}"); $res = $stmt->execute(); while ($row = $stmt->fetch()) { $id = intval($row['id']); $parent = intval($row['structure_parent']); // The $parent is only relevant if it exists and is published. if (in_array($parent, $availableStructures)) { $this->treeParents[$contenttypeslug][$id] = $parent; $this->treeChildren[$parent][] = "{$contenttypeslug}/{$id}"; } } } } $this->linksLoaded = true; }
/** * Get the relations for one or more units of content, return the array with the taxonomy attached. * * @param array $content * * @return array $content */ protected function getRelation($content) { $tablename = $this->getTablename("relations"); $ids = util::array_pluck($content, 'id'); if (empty($ids)) { return; } // Get the contenttype from first $content $contenttype = $content[util::array_first_key($content)]->contenttype['slug']; $query = sprintf("SELECT * FROM %s WHERE from_contenttype=? AND from_id IN (?) ORDER BY id", $tablename); $params = array($contenttype, $ids); $paramTypes = array(\PDO::PARAM_STR, DoctrineConn::PARAM_INT_ARRAY); $rows = $this->app['db']->executeQuery($query, $params, $paramTypes)->fetchAll(); foreach ($rows as $row) { $content[$row['from_id']]->setRelation($row['to_contenttype'], $row['to_id']); } // switch it, flip it and reverse it. wop wop wop. $query = sprintf("SELECT * FROM %s WHERE to_contenttype=? AND to_id IN (?) ORDER BY id", $tablename); $params = array($contenttype, $ids); $paramTypes = array(\PDO::PARAM_STR, DoctrineConn::PARAM_INT_ARRAY); $rows = $this->app['db']->executeQuery($query, $params, $paramTypes)->fetchAll(); foreach ($rows as $row) { $content[$row['to_id']]->setRelation($row['from_contenttype'], $row['from_id']); } }
public function getRepeaters($content) { $ids = util::array_pluck($content, 'id'); if (empty($ids)) { return; } // Get the contenttype from first $content $contenttypeslug = $content[util::array_first_key($content)]->contenttype['slug']; $contenttype = $this->getContentType($contenttypeslug); $repo = $this->app['storage']->getRepository('Bolt\\Storage\\Entity\\FieldValue'); foreach ($ids as $id) { foreach ($contenttype['fields'] as $fieldkey => $field) { if ($field['type'] == 'repeater') { $collection = new RepeatingFieldCollection($this->app['storage'], $field); $existingFields = $repo->getExistingFields($id, $contenttypeslug, $fieldkey) ?: []; foreach ($existingFields as $group => $ids) { $collection->addFromReferences($ids, $group); } $content[$id]->setValue($fieldkey, $collection); } } } }
/** * Search through a single contenttype. * * Search, weigh and return the results. * * @param $query * @param $contenttype * @param $fields * @param array $filter * * @return \Bolt\Legacy\Content */ private function searchSingleContentType($query, $contenttype, $fields, array $filter = null) { // This could be even more configurable // (see also Content->getFieldWeights) $searchableTypes = ['text', 'textarea', 'html', 'markdown']; $table = $this->getContentTypeCollection($contenttype); // Build fields 'WHERE' $fieldsWhere = []; foreach ($fields as $field => $fieldconfig) { if (in_array($fieldconfig['type'], $searchableTypes)) { foreach ($query['words'] as $word) { $fieldsWhere[] = sprintf('%s.%s LIKE %s', $table, $field, $this->app['db']->quote('%' . $word . '%')); } } } // make taxonomies work $taxonomytable = $this->getTablename('taxonomy'); $taxonomies = $this->getContentTypeTaxonomy($contenttype); $tagsWhere = []; $tagsQuery = ''; foreach ($taxonomies as $taxonomy) { if ($taxonomy['behaves_like'] == 'tags') { foreach ($query['words'] as $word) { $tagsWhere[] = sprintf('%s.slug LIKE %s', $taxonomytable, $this->app['db']->quote('%' . $word . '%')); } } } // only add taxonomies if they exist if (!empty($taxonomies) && !empty($tagsWhere)) { $tagsQueryA = sprintf("%s.contenttype = '%s'", $taxonomytable, $contenttype); $tagsQueryB = implode(' OR ', $tagsWhere); $tagsQuery = sprintf(' OR (%s AND (%s))', $tagsQueryA, $tagsQueryB); } // Build filter 'WHERE" // @todo make relations work as well $filterWhere = []; if (!is_null($filter)) { foreach ($fields as $field => $fieldconfig) { if (isset($filter[$field])) { $this->parseWhereParameter($table . '.' . $field, $filter[$field], $filterWhere); } } } // Build actual where $where = []; $where[] = sprintf("%s.status = 'published'", $table); $where[] = '(( ' . implode(' OR ', $fieldsWhere) . ' ) ' . $tagsQuery . ' )'; $where = array_merge($where, $filterWhere); // Build SQL query $select = sprintf('SELECT %s.id FROM %s LEFT JOIN %s ON %s.id = %s.content_id WHERE %s GROUP BY %s.id', $table, $table, $taxonomytable, $table, $taxonomytable, implode(' AND ', $where), $table); // Run Query $results = $this->app['db']->fetchAll($select); if (!empty($results)) { $ids = implode(' || ', util::array_pluck($results, 'id')); $results = $this->getContent($contenttype, ['id' => $ids, 'returnsingle' => false]); // Convert and weight foreach ($results as $result) { $result->weighSearchResult($query); } } return $results; }
/** * @author Xiao-Hu Tai * @param \Bolt\Content $record The record to search similar content for. * @param array $options Options for custom queries. * * @return array Returns an array with the elements sorted by similarity. */ function relatedContentByTags($record, $options = array()) { $app = $this->app; $limit = isset($options['limit']) ? $options['limit'] : $this->config['limit']; $tablePrefix = $app['config']->get('general/database/prefix', 'bolt_'); $taxonomyTable = sprintf('%staxonomy', $tablePrefix); $contenttypes = $app['config']->get('contenttypes'); $filter = isset($options['contenttypes']) ? $options['contenttypes'] : false; // if set, filter contenttypes if ($filter) { $filterContenttypes = array(); foreach ($filter as $contenttypeName) { if (isset($contenttypes[$contenttypeName])) { $filterContenttypes[$contenttypeName] = $contenttypes[$contenttypeName]; } } if ($filterContenttypes) { $contenttypes = $filterContenttypes; } } // Get all taxonomies that behave like tags and their values from $record. $tagsValues = array(); $tagsTaxonomies = array(); // If no taxonomies exist, then no matching items exist if (!isset($record->contenttype['taxonomy'])) { return array(); } foreach ($record->contenttype['taxonomy'] as $key) { if ($app['config']->get('taxonomy/' . $key . '/behaves_like') == 'tags') { // only useful if values exist, otherwise just skip this taxonomy if ($record->taxonomy[$key]) { $tagsValues[$key] = array_values($record->taxonomy[$key]); $tagsTaxonomies[] = $key; } } } // Make the basic WHERE query for all behaves-like-tags values in $record. $queryWhere = array(); foreach ($tagsValues as $tagName => $values) { $subqueryWhere = array(); foreach ($values as $word) { $subqueryWhere[] = sprintf('%s.slug = "%s"', $taxonomyTable, $word); } $temp = sprintf('%s.taxonomytype = "%s"', $taxonomyTable, $tagName); $temp .= sprintf(' AND (%s)', implode(' OR ', $subqueryWhere)); $queryWhere[] = $temp; } $queryWhere = implode(' OR ', $queryWhere); // Get all contenttypes (database tables) that have a similar behaves-like-tags taxonomies like $record $tables = array(); foreach ($contenttypes as $key => $contenttype) { foreach ($contenttype['taxonomy'] as $taxonomyKey) { if (in_array($taxonomyKey, $tagsTaxonomies)) { $tables[] = $contenttype['slug']; break; } } } // Fetch results for every proper contenttype $results = array(); foreach ($tables as $name) { $table = sprintf('%s%s', $tablePrefix, $name); $querySelect = ''; $querySelect .= sprintf('SELECT %s.id FROM %s', $table, $table); $querySelect .= sprintf(' LEFT JOIN %s', $taxonomyTable); $querySelect .= sprintf(' ON %s.id = %s.content_id', $table, $taxonomyTable); $querySelect .= sprintf(' WHERE %s.status = "published"', $table); if ($name == $record->contenttype['slug']) { $querySelect .= sprintf('AND %s.id != ' . $record->id, $table); } $querySelect .= sprintf(' AND %s.contenttype = "%s"', $taxonomyTable, $name); $querySelect .= sprintf(' AND (%s)', $queryWhere); $queryResults = $app['db']->fetchAll($querySelect); if (!empty($queryResults)) { $ids = implode(' || ', \utilphp\util::array_pluck($queryResults, 'id')); $contents = $app['storage']->getContent($name, array('id' => $ids, 'returnsingle' => false)); $results = array_merge($results, $contents); } } // Add similarities by tags and difference in publication dates. foreach ($results as $result) { $similarity = $this->calculateTaxonomySimilarity($record, $result, $tagsTaxonomies, $tagsValues, $options); $diff = $this->calculatePublicationDiff($record, $result); $result->similarity = $similarity; $result->diff = $diff; } // Sort results usort($results, array($this, 'compareSimilarity')); // Limit results $results = array_slice($results, 0, $limit); return $results; }
public function test_array_pluck() { $array = array(array('name' => 'Bob', 'age' => 37), array('name' => 'Fred', 'age' => 37), array('name' => 'Jane', 'age' => 29), array('name' => 'Brandon', 'age' => 20), array('age' => 41)); $obj_array = array('bob' => (object) array('name' => 'Bob', 'age' => 37), 'fred' => (object) array('name' => 'Fred', 'age' => 37), 'jane' => (object) array('name' => 'Jane', 'age' => 29), 'brandon' => (object) array('name' => 'Brandon', 'age' => 20), 'invalid' => (object) array('age' => 41)); $obj_array_expect = array('bob' => 'Bob', 'fred' => 'Fred', 'jane' => 'Jane', 'brandon' => 'Brandon'); $this->assertEquals(array('Bob', 'Fred', 'Jane', 'Brandon'), util::array_pluck($array, 'name')); $this->assertEquals(array('Bob', 'Fred', 'Jane', 'Brandon', array('age' => 41)), util::array_pluck($array, 'name', TRUE, FALSE)); $this->assertEquals($obj_array_expect, util::array_pluck($obj_array, 'name')); $this->assertEquals(array('Bob', 'Fred', 'Jane', 'Brandon'), util::array_pluck($obj_array, 'name', FALSE)); $expected = array('Bob', 'Fred', 'Jane', 'Brandon', 'invalid' => (object) array('age' => 41)); $this->assertEquals($expected, util::array_pluck($obj_array, 'name', FALSE, FALSE)); $expected = array('Bob', 'Fred', 'Jane', 'Brandon', array('age' => 41)); $this->assertEquals($expected, util::array_pluck($array, 'name', false, false)); }