182 lines
5.5 KiB
PHP
182 lines
5.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package Grav\Common
|
|
*
|
|
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
* @license MIT License; see LICENSE file for details.
|
|
*/
|
|
|
|
namespace Grav\Common;
|
|
|
|
use Grav\Common\Config\Config;
|
|
use Grav\Common\Language\Language;
|
|
use Grav\Common\Page\Collection;
|
|
use Grav\Common\Page\Interfaces\PageInterface;
|
|
use function is_string;
|
|
|
|
/**
|
|
* The Taxonomy object is a singleton that holds a reference to a 'taxonomy map'. This map is
|
|
* constructed as a multidimensional array.
|
|
*
|
|
* uses the taxonomy defined in the site.yaml file and is built when the page objects are recursed.
|
|
* Basically every time a page is found that has taxonomy references, an entry to the page is stored in
|
|
* the taxonomy map. The map has the following format:
|
|
*
|
|
* [taxonomy_type][taxonomy_value][page_path]
|
|
*
|
|
* For example:
|
|
*
|
|
* [category][blog][path/to/item1]
|
|
* [tag][grav][path/to/item1]
|
|
* [tag][grav][path/to/item2]
|
|
* [tag][dog][path/to/item3]
|
|
*/
|
|
class Taxonomy
|
|
{
|
|
/** @var array */
|
|
protected $taxonomy_map;
|
|
/** @var Grav */
|
|
protected $grav;
|
|
/** @var Language */
|
|
protected $language;
|
|
|
|
/**
|
|
* Constructor that resets the map
|
|
*
|
|
* @param Grav $grav
|
|
*/
|
|
public function __construct(Grav $grav)
|
|
{
|
|
$this->grav = $grav;
|
|
$this->language = $grav['language'];
|
|
$this->taxonomy_map[$this->language->getLanguage()] = [];
|
|
}
|
|
|
|
/**
|
|
* Takes an individual page and processes the taxonomies configured in its header. It
|
|
* then adds those taxonomies to the map
|
|
*
|
|
* @param PageInterface $page the page to process
|
|
* @param array|null $page_taxonomy
|
|
*/
|
|
public function addTaxonomy(PageInterface $page, $page_taxonomy = null)
|
|
{
|
|
if (!$page->published()) {
|
|
return;
|
|
}
|
|
|
|
if (!$page_taxonomy) {
|
|
$page_taxonomy = $page->taxonomy();
|
|
}
|
|
|
|
if (empty($page_taxonomy)) {
|
|
return;
|
|
}
|
|
|
|
/** @var Config $config */
|
|
$config = $this->grav['config'];
|
|
$taxonomies = (array)$config->get('site.taxonomies');
|
|
foreach ($taxonomies as $taxonomy) {
|
|
// Skip invalid taxonomies.
|
|
if (!\is_string($taxonomy)) {
|
|
continue;
|
|
}
|
|
$current = $page_taxonomy[$taxonomy] ?? null;
|
|
foreach ((array)$current as $item) {
|
|
$this->iterateTaxonomy($page, $taxonomy, '', $item);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iterate through taxonomy fields
|
|
*
|
|
* Reduces [taxonomy_type] to dot-notation where necessary
|
|
*
|
|
* @param PageInterface $page The Page to process
|
|
* @param string $taxonomy Taxonomy type to add
|
|
* @param string $key Taxonomy type to concatenate
|
|
* @param iterable|string $value Taxonomy value to add or iterate
|
|
* @return void
|
|
*/
|
|
public function iterateTaxonomy(PageInterface $page, string $taxonomy, string $key, $value)
|
|
{
|
|
if (is_iterable($value)) {
|
|
foreach ($value as $identifier => $item) {
|
|
$identifier = "{$key}.{$identifier}";
|
|
$this->iterateTaxonomy($page, $taxonomy, $identifier, $item);
|
|
}
|
|
} elseif (is_string($value)) {
|
|
if (!empty($key)) {
|
|
$taxonomy .= $key;
|
|
}
|
|
$active = $this->language->getLanguage();
|
|
$this->taxonomy_map[$active][$taxonomy][(string) $value][$page->path()] = ['slug' => $page->slug()];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a new Page object with the sub-pages containing all the values set for a
|
|
* particular taxonomy.
|
|
*
|
|
* @param array $taxonomies taxonomies to search, eg ['tag'=>['animal','cat']]
|
|
* @param string $operator can be 'or' or 'and' (defaults to 'and')
|
|
* @return Collection Collection object set to contain matches found in the taxonomy map
|
|
*/
|
|
public function findTaxonomy($taxonomies, $operator = 'and')
|
|
{
|
|
$matches = [];
|
|
$results = [];
|
|
$active = $this->language->getLanguage();
|
|
|
|
foreach ((array)$taxonomies as $taxonomy => $items) {
|
|
foreach ((array)$items as $item) {
|
|
$matches[] = $this->taxonomy_map[$active][$taxonomy][$item] ?? [];
|
|
}
|
|
}
|
|
|
|
if (strtolower($operator) === 'or') {
|
|
foreach ($matches as $match) {
|
|
$results = array_merge($results, $match);
|
|
}
|
|
} else {
|
|
$results = $matches ? array_pop($matches) : [];
|
|
foreach ($matches as $match) {
|
|
$results = array_intersect_key($results, $match);
|
|
}
|
|
}
|
|
|
|
return new Collection($results, ['taxonomies' => $taxonomies]);
|
|
}
|
|
|
|
/**
|
|
* Gets and Sets the taxonomy map
|
|
*
|
|
* @param array|null $var the taxonomy map
|
|
* @return array the taxonomy map
|
|
*/
|
|
public function taxonomy($var = null)
|
|
{
|
|
$active = $this->language->getLanguage();
|
|
|
|
if ($var) {
|
|
$this->taxonomy_map[$active] = $var;
|
|
}
|
|
|
|
return $this->taxonomy_map[$active] ?? [];
|
|
}
|
|
|
|
/**
|
|
* Gets item keys per taxonomy
|
|
*
|
|
* @param string $taxonomy taxonomy name
|
|
* @return array keys of this taxonomy
|
|
*/
|
|
public function getTaxonomyItemKeys($taxonomy)
|
|
{
|
|
$active = $this->language->getLanguage();
|
|
return isset($this->taxonomy_map[$active][$taxonomy]) ? array_keys($this->taxonomy_map[$active][$taxonomy]) : [];
|
|
}
|
|
}
|