Commit 69da203d authored by Markus Kalkbrenner's avatar Markus Kalkbrenner Committed by GitHub

Issue #378 support JSON Facet API (#590)

solves issue #378 support JSON Facet API
parent e9844b8e
......@@ -6,8 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
### Added
- Support for JSON Facet API
### Changed
- Constants FacetSet::FACET_* became FacetSetInterface::FACET_*
### Deprecated
......
......@@ -9,15 +9,8 @@ use Solarium\Core\Configurable;
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters
*/
abstract class AbstractFacet extends Configurable
abstract class AbstractFacet extends Configurable implements FacetInterface
{
/**
* Exclude tags for this facet.
*
* @var array
*/
protected $excludes = [];
/**
* Must be implemented by the facet types and return one of the constants.
*
......@@ -48,106 +41,4 @@ abstract class AbstractFacet extends Configurable
{
return $this->setOption('key', $value);
}
/**
* Add an exclude tag.
*
* @param string $tag
*
* @return self Provides fluent interface
*/
public function addExclude($tag)
{
$this->excludes[$tag] = true;
return $this;
}
/**
* Add multiple exclude tags.
*
* @param array $excludes
*
* @return self Provides fluent interface
*/
public function addExcludes(array $excludes)
{
foreach ($excludes as $exclude) {
$this->addExclude($exclude);
}
return $this;
}
/**
* Get all excludes.
*
* @return array
*/
public function getExcludes()
{
return array_keys($this->excludes);
}
/**
* Remove a single exclude tag.
*
* @param string $exclude
*
* @return self Provides fluent interface
*/
public function removeExclude($exclude)
{
if (isset($this->excludes[$exclude])) {
unset($this->excludes[$exclude]);
}
return $this;
}
/**
* Remove all excludes.
*
* @return self Provides fluent interface
*/
public function clearExcludes()
{
$this->excludes = [];
return $this;
}
/**
* Set multiple excludes.
*
* This overwrites any existing excludes
*
* @param array $excludes
*/
public function setExcludes($excludes)
{
$this->clearExcludes();
$this->addExcludes($excludes);
}
/**
* Initialize options.
*/
protected function init()
{
foreach ($this->options as $name => $value) {
switch ($name) {
case 'key':
$this->setKey($value);
break;
case 'exclude':
if (!is_array($value)) {
$value = explode(',', $value);
}
$this->setExcludes($value);
unset($this->options['exclude']);
break;
}
}
}
}
<?php
namespace Solarium\Component\Facet;
/**
* Facet query.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Field_Value_Faceting_Parameters
*/
abstract class AbstractField extends AbstractFacet
{
/**
* Facet sort type index.
*/
const SORT_INDEX = 'index';
/**
* Facet sort type count.
*/
const SORT_COUNT = 'count';
/**
* Default options.
*
* @var array
*/
protected $options = [
'field' => 'id',
];
/**
* Set the field name.
*
* @param string $field
*
* @return self Provides fluent interface
*/
public function setField($field)
{
return $this->setOption('field', $field);
}
/**
* Get the field name.
*
* @return string
*/
public function getField()
{
return $this->getOption('field');
}
/**
* Set the facet sort order.
*
* Use one of the SORT_* constants as the value
*
* @param string $sort
*
* @return self Provides fluent interface
*/
public function setSort($sort)
{
return $this->setOption('sort', $sort);
}
/**
* Get the facet sort order.
*
* @return string
*/
public function getSort()
{
return $this->getOption('sort');
}
/**
* Limit the terms for faceting by a prefix.
*
* @param string $prefix
*
* @return self Provides fluent interface
*/
public function setPrefix($prefix)
{
return $this->setOption('prefix', $prefix);
}
/**
* Get the facet prefix.
*
* @return string
*/
public function getPrefix()
{
return $this->getOption('prefix');
}
/**
* Set the facet limit.
*
* @param mixed $limit
*
* @return self Provides fluent interface
*/
public function setLimit($limit)
{
return $this->setOption('limit', $limit);
}
/**
* Get the facet limit.
*
* @return string
*/
public function getLimit()
{
return $this->getOption('limit');
}
/**
* Set the facet offset.
*
* @param int $offset
*
* @return self Provides fluent interface
*/
public function setOffset($offset)
{
return $this->setOption('offset', $offset);
}
/**
* Get the facet offset.
*
* @return int
*/
public function getOffset()
{
return $this->getOption('offset');
}
/**
* Set the facet mincount.
*
* @param int $minCount
*
* @return self Provides fluent interface
*/
public function setMinCount($minCount)
{
return $this->setOption('mincount', $minCount);
}
/**
* Get the facet mincount.
*
* @return int
*/
public function getMinCount()
{
return $this->getOption('mincount');
}
/**
* Set the missing count option.
*
* @param bool $missing
*
* @return self Provides fluent interface
*/
public function setMissing($missing)
{
return $this->setOption('missing', $missing);
}
/**
* Get the facet missing option.
*
* @return bool
*/
public function getMissing()
{
return $this->getOption('missing');
}
/**
* Set the facet method.
*
* Use one of the METHOD_* constants as value
*
* @param string $method
*
* @return self Provides fluent interface
*/
public function setMethod($method)
{
return $this->setOption('method', $method);
}
/**
* Get the facet method.
*
* @return string
*/
public function getMethod()
{
return $this->getOption('method');
}
}
<?php
namespace Solarium\Component\Facet;
/**
* Facet range.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range
*/
abstract class AbstractRange extends AbstractFacet
{
/**
* Value for the 'other' option.
*/
const OTHER_BEFORE = 'before';
/**
* Value for the 'other' option.
*/
const OTHER_AFTER = 'after';
/**
* Value for the 'other' option.
*/
const OTHER_BETWEEN = 'between';
/**
* Value for the 'other' option.
*/
const OTHER_ALL = 'all';
/**
* Value for the 'other' option.
*/
const OTHER_NONE = 'none';
/**
* Value for the 'include' option.
*/
const INCLUDE_LOWER = 'lower';
/**
* Value for the 'include' option.
*/
const INCLUDE_UPPER = 'upper';
/**
* Value for the 'include' option.
*/
const INCLUDE_EDGE = 'edge';
/**
* Value for the 'include' option.
*/
const INCLUDE_OUTER = 'outer';
/**
* Value for the 'include' option.
*/
const INCLUDE_ALL = 'all';
/**
* Set the field name.
*
* @param string $field
*
* @return self Provides fluent interface
*/
public function setField($field)
{
return $this->setOption('field', $field);
}
/**
* Get the field name.
*
* @return string
*/
public function getField()
{
return $this->getOption('field');
}
/**
* Set the lower bound of the range.
*
* @param string $start
*
* @return self Provides fluent interface
*/
public function setStart($start)
{
return $this->setOption('start', $start);
}
/**
* Get the lower bound of the range.
*
* @return string
*/
public function getStart()
{
return $this->getOption('start');
}
/**
* Set the upper bound of the range.
*
* @param string $end
*
* @return self Provides fluent interface
*/
public function setEnd($end)
{
return $this->setOption('end', $end);
}
/**
* Get the upper bound of the range.
*
* @return string
*/
public function getEnd()
{
return $this->getOption('end');
}
/**
* Set range gap.
*
* The size of each range expressed as a value to be added to the lower bound
*
* @param string $gap
*
* @return self Provides fluent interface
*/
public function setGap($gap)
{
return $this->setOption('gap', $gap);
}
/**
* Get range gap.
*
* The size of each range expressed as a value to be added to the lower bound
*
* @return string
*/
public function getGap()
{
return $this->getOption('gap');
}
/**
* Set hardend option.
*
* A Boolean parameter instructing Solr what to do in the event that facet.range.gap
* does not divide evenly between facet.range.start and facet.range.end
*
* @param bool $hardend
*
* @return self Provides fluent interface
*/
public function setHardend($hardend)
{
return $this->setOption('hardend', $hardend);
}
/**
* Get hardend option.
*
* @return bool
*/
public function getHardend()
{
return $this->getOption('hardend');
}
/**
* Set other counts.
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $other
*
* @return self Provides fluent interface
*/
public function setOther($other)
{
if (is_string($other)) {
$other = explode(',', $other);
$other = array_map('trim', $other);
}
return $this->setOption('other', $other);
}
/**
* Get other counts.
*
* @return array
*/
public function getOther()
{
$other = $this->getOption('other');
if (null === $other) {
$other = [];
}
return $other;
}
/**
* Set include option.
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $include
*
* @return self Provides fluent interface
*/
public function setInclude($include)
{
if (is_string($include)) {
$include = explode(',', $include);
$include = array_map('trim', $include);
}
return $this->setOption('include', $include);
}
/**
* Get include option.
*
* @return array
*/
public function getInclude()
{
$include = $this->getOption('include');
if (null === $include) {
$include = [];
}
return $include;
}
/**
* Initialize options.
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
*/
protected function init()
{
foreach ($this->options as $name => $value) {
switch ($name) {
case 'include':
$this->setInclude($value);
break;
case 'other':
$this->setOther($value);
break;
}
}
}
}
<?php
namespace Solarium\Component\Facet;
/**
* Exclude tags for facets.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters
*/
interface ExcludeTagsInterface
{
/**
* Add an exclude tag.
*
* @param string $tag
*
* @return self Provides fluent interface
*/
public function addExclude($tag);
/**
* Add multiple exclude tags.
*
* @param array $excludes
*
* @return self Provides fluent interface
*/
public function addExcludes(array $excludes);
/**
* Get all excludes.
*
* @return array
*/
public function getExcludes();
/**
* Remove a single exclude tag.
*
* @param string $exclude
*
* @return self Provides fluent interface
*/
public function removeExclude($exclude);
/**
* Remove all excludes.
*
* @return self Provides fluent interface
*/
public function clearExcludes();
/**
* Set multiple excludes.
*
* This overwrites any existing excludes
*
* @param array $excludes
*/
public function setExcludes($excludes);
}
<?php
namespace Solarium\Component\Facet;
/**
* Exclude tags for facets.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters
*/
trait ExcludeTagsTrait
{
/**
* Exclude tags for this facet.
*
* @var array
*/
protected $excludes = [];
/**
* Add an exclude tag.
*
* @param string $tag
*
* @return self Provides fluent interface
*/
public function addExclude($tag)
{
$this->excludes[$tag] = true;
return $this;
}
/**
* Add multiple exclude tags.
*
* @param array $excludes
*
* @return self Provides fluent interface
*/
public function addExcludes(array $excludes)
{
foreach ($excludes as $exclude) {
$this->addExclude($exclude);
}
return $this;
}
/**
* Get all excludes.
*
* @return array
*/
public function getExcludes()
{
return array_keys($this->excludes);
}
/**
* Remove a single exclude tag.
*
* @param string $exclude
*
* @return self Provides fluent interface
*/
public function removeExclude($exclude)
{
if (isset($this->excludes[$exclude])) {
unset($this->excludes[$exclude]);
}
return $this;
}
/**
* Remove all excludes.
*
* @return self Provides fluent interface
*/
public function clearExcludes()
{
$this->excludes = [];
return $this;
}
/**
* Set multiple excludes.
*
* This overwrites any existing excludes
*
* @param array $excludes
*/
public function setExcludes($excludes)
{
$this->clearExcludes();
$this->addExcludes($excludes);
}
/**
* Initialize options.
*/
protected function init()
{
foreach ($this->options as $name => $value) {
switch ($name) {
case 'exclude':
if (!is_array($value)) {
$value = explode(',', $value);
}
$this->setExcludes($value);
unset($this->options['exclude']);
break;
}
}
}
}
<?php
namespace Solarium\Component\Facet;
/**
* Facet base class.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters
*/
interface FacetInterface
{
/**
* Must be implemented by the facet types and return one of the constants.
*
* @abstract
*
* @return string
*/
public function getType();
/**
* Get key value.
*
* @return string
*/
public function getKey();
/**
* Set key value.
*
* @param string $value
*
* @return FacetInterface
*/
public function setKey($value);
}
......@@ -2,24 +2,16 @@
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
/**
* Facet query.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Field_Value_Faceting_Parameters
*/
class Field extends AbstractFacet
class Field extends AbstractField implements ExcludeTagsInterface
{
/**
* Facet sort type index.
*/
const SORT_INDEX = 'index';
/**
* Facet sort type count.
*/
const SORT_COUNT = 'count';
use ExcludeTagsTrait;
/**
* Facet method enum.
......@@ -31,15 +23,6 @@ class Field extends AbstractFacet
*/
const METHOD_FC = 'fc';
/**
* Default options.
*
* @var array
*/
protected $options = [
'field' => 'id',
];
/**
* Get the facet type.
*
......@@ -47,75 +30,7 @@ class Field extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_FIELD;
}
/**
* Set the field name.
*
* @param string $field
*
* @return self Provides fluent interface
*/
public function setField($field)
{
return $this->setOption('field', $field);
}
/**
* Get the field name.
*
* @return string
*/
public function getField()
{
return $this->getOption('field');
}
/**
* Set the facet sort order.
*
* Use one of the SORT_* constants as the value
*
* @param string $sort
*
* @return self Provides fluent interface
*/
public function setSort($sort)
{
return $this->setOption('sort', $sort);
}
/**
* Get the facet sort order.
*
* @return string
*/
public function getSort()
{
return $this->getOption('sort');
}
/**
* Limit the terms for faceting by a prefix.
*
* @param string $prefix
*
* @return self Provides fluent interface
*/
public function setPrefix($prefix)
{
return $this->setOption('prefix', $prefix);
}
/**
* Get the facet prefix.
*
* @return string
*/
public function getPrefix()
{
return $this->getOption('prefix');
return FacetSetInterface::FACET_FIELD;
}
/**
......@@ -169,116 +84,4 @@ class Field extends AbstractFacet
{
return $this->getOption('containsignorecase');
}
/**
* Set the facet limit.
*
* @param mixed $limit
*
* @return self Provides fluent interface
*/
public function setLimit($limit)
{
return $this->setOption('limit', $limit);
}
/**
* Get the facet limit.
*
* @return string
*/
public function getLimit()
{
return $this->getOption('limit');
}
/**
* Set the facet offset.
*
* @param int $offset
*
* @return self Provides fluent interface
*/
public function setOffset($offset)
{
return $this->setOption('offset', $offset);
}
/**
* Get the facet offset.
*
* @return int
*/
public function getOffset()
{
return $this->getOption('offset');
}
/**
* Set the facet mincount.
*
* @param int $minCount
*
* @return self Provides fluent interface
*/
public function setMinCount($minCount)
{
return $this->setOption('mincount', $minCount);
}
/**
* Get the facet mincount.
*
* @return int
*/
public function getMinCount()
{
return $this->getOption('mincount');
}
/**
* Set the missing count option.
*
* @param bool $missing
*
* @return self Provides fluent interface
*/
public function setMissing($missing)
{
return $this->setOption('missing', $missing);
}
/**
* Get the facet missing option.
*
* @return bool
*/
public function getMissing()
{
return $this->getOption('missing');
}
/**
* Set the facet method.
*
* Use one of the METHOD_* constants as value
*
* @param string $method
*
* @return self Provides fluent interface
*/
public function setMethod($method)
{
return $this->setOption('method', $method);
}
/**
* Get the facet method.
*
* @return string
*/
public function getMethod()
{
return $this->getOption('method');
}
}
......@@ -2,7 +2,7 @@
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
/**
* Facet interval.
......@@ -11,6 +11,10 @@ use Solarium\Component\FacetSet;
*/
class Interval extends AbstractFacet
{
use ExcludeTagsTrait {
init as excludeTagsInit;
}
/**
* Get the facet type.
*
......@@ -18,7 +22,7 @@ class Interval extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_INTERVAL;
return FacetSetInterface::FACET_INTERVAL;
}
/**
......@@ -86,7 +90,7 @@ class Interval extends AbstractFacet
*/
protected function init()
{
parent::init();
$this->excludeTagsInit();
foreach ($this->options as $name => $value) {
switch ($name) {
......
<?php
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSetInterface;
/**
* JSON facet aggregation.
*
* @see https://lucene.apache.org/solr/guide/7_3/json-facet-api.html
*/
class JsonAggregation extends AbstractFacet implements JsonFacetInterface
{
/**
* Get the facet type.
*
* @return string
*/
public function getType()
{
return FacetSetInterface::JSON_FACET_AGGREGATION;
}
/**
* Set the function string.
*
* This overwrites the current value
*
* @param string $function
*
* @return self Provides fluent interface
*/
public function setFunction($function)
{
return $this->setOption('function', $function);
}
/**
* Get the function string.
*
* @return string
*/
public function getFunction()
{
return $this->getOption('function');
}
/**
* Serializes nested facets as option "facet" and returns that array structure.
*
* @return array|string
*/
public function serialize()
{
return $this->getFunction();
}
}
<?php
namespace Solarium\Component\Facet;
/**
* Json facets.
*
* @see https://lucene.apache.org/solr/guide/7_3/json-facet-api.html
*/
interface JsonFacetInterface
{
/**
* Serializes nested facets as option "facet" and returns that array structure.
*
* @return array|string
*/
public function serialize();
}
<?php
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSetInterface;
use Solarium\Component\FacetSetTrait;
use Solarium\Core\Query\Helper;
use Solarium\Exception\InvalidArgumentException;
/**
* Json facets.
*
* @see https://lucene.apache.org/solr/guide/7_3/json-facet-api.html
*/
trait JsonFacetTrait
{
use FacetSetTrait {
addFacet as facetSetAddFacet;
removeFacet as facetSetRemoveFacet;
clearFacets as facetSetClearFacets;
}
/**
* Facet type mapping.
*
* @var array
*/
protected $facetTypes = [
FacetSetInterface::JSON_FACET_TERMS => 'Solarium\Component\Facet\JsonTerms',
FacetSetInterface::JSON_FACET_QUERY => 'Solarium\Component\Facet\JsonQuery',
FacetSetInterface::JSON_FACET_RANGE => 'Solarium\Component\Facet\JsonRange',
FacetSetInterface::JSON_FACET_AGGREGATION => 'Solarium\Component\Facet\JsonAggregation',
];
/**
* Get the domain filter.
*
* @return string
*/
public function getDomainFilter()
{
$domain = $this->getOption('domain');
if ($domain && isset($domain['filter'])) {
return $domain['filter'];
}
}
/**
* Set the domain filter query string.
*
* This overwrites the current value.
*
* @param string $query
* @param array $bind Bind values for placeholders in the query string
*
* @return self Provides fluent interface
*/
public function setDomainFilterQuery(string $query, array $bind = null)
{
if (null !== $bind) {
$helper = new Helper();
$query = $helper->assemble($query, $bind);
}
$filter = $this->getDomainFilter();
if (!$filter || is_string($filter)) {
return $this->setOption('domain', ['filter' => $query]);
} else {
foreach ($filter as &$param_or_query) {
if (is_string($param_or_query)) {
$param_or_query = $query;
return $this->setOption('domain', ['filter' => $filter]);
}
}
$filter[] = $query;
return $this->setOption('domain', ['filter' => $filter]);
}
}
/**
* Adds a domain filter parameter.
*
* @param string $param
*
* @return self Provides fluent interface
*/
public function addDomainFilterParameter(string $param)
{
$filter = $this->getDomainFilter();
if (!$filter) {
return $this->setOption('domain', ['filter' => ['param' => $param]]);
} elseif (is_string($filter) || 1 == count($filter)) {
return $this->setOption('domain', ['filter' => [$filter, ['param' => $param]]]);
} else {
foreach ($filter as &$param_or_query) {
if (is_array($param_or_query) && $param_or_query['param'] == $param) {
return $this;
}
}
$filter[] = ['param' => $param];
return $this->setOption('domain', ['filter' => $filter]);
}
}
/**
* Serializes nested facets as option "facet" and returns that array structure.
*
* @return array|string
*/
public function serialize()
{
// Strip 'json_' prefix.
$this->setOption('type', substr($this->getType(), 5));
$facets = [];
foreach ($this->getFacets() as $key => $facet) {
$facets[$key] = $facet->serialize();
}
if ($facets) {
$this->setOption('facet', $facets);
} elseif (isset($this->options['facet'])) {
unset($this->options['facet']);
}
$options = $this->getOptions();
unset($options['key']);
return $options;
}
/**
* Add a facet.
*
*
* @param FacetInterface|array $facet
*
* @throws InvalidArgumentException
*
* @return self Provides fluent interface
*/
public function addFacet($facet)
{
if ($facet instanceof JsonFacetInterface) {
$this->facetSetAddFacet($facet);
$this->serialize();
return $this;
} else {
throw new InvalidArgumentException('Only JSON facets can be nested.');
}
}
/**
* Remove a single facet.
*
* You can remove a facet by passing its key or the facet instance
*
* @param string|FacetInterface $facet
*
* @return self Provides fluent interface
*/
public function removeFacet($facet)
{
$this->facetSetRemoveFacet($facet);
$this->serialize();
return $this;
}
/**
* Remove all facets.
*
* @return self Provides fluent interface
*/
public function clearFacets()
{
$this->facetSetClearFacets();
$this->serialize();
return $this;
}
}
<?php
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSetInterface;
use Solarium\Core\Query\Helper;
/**
* Facet query.
*
* @see https://lucene.apache.org/solr/guide/7_3/json-facet-api.html
*/
class JsonQuery extends AbstractFacet implements JsonFacetInterface, FacetSetInterface
{
use JsonFacetTrait;
/**
* Default options.
*
* @var array
*/
protected $options = [
'q' => '*:*',
];
/**
* Get the facet type.
*
* @return string
*/
public function getType()
{
return FacetSetInterface::JSON_FACET_QUERY;
}
/**
* Set the query string.
*
* This overwrites the current value
*
* @param string $query
* @param array $bind Bind values for placeholders in the query string
*
* @return self Provides fluent interface
*/
public function setQuery($query, $bind = null)
{
if (null !== $bind) {
$helper = new Helper();
$query = $helper->assemble($query, $bind);
}
return $this->setOption('q', $query);
}
/**
* Get the query string.
*
* @return string
*/
public function getQuery()
{
return $this->getOption('q');
}
}
<?php
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSetInterface;
/**
* Facet range.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range
*/
class JsonRange extends AbstractRange implements JsonFacetInterface, FacetSetInterface
{
use JsonFacetTrait {
init as jsonFacetInit;
}
/**
* Get the facet type.
*
* @return string
*/
public function getType()
{
return FacetSetInterface::JSON_FACET_RANGE;
}
/**
* Initialize options.
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
*/
protected function init()
{
parent::init();
$this->jsonFacetInit();
}
}
<?php
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSetInterface;
/**
* Facet query.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Field_Value_Faceting_Parameters
*/
class JsonTerms extends AbstractField implements JsonFacetInterface, FacetSetInterface
{
use JsonFacetTrait;
/**
* Facet method "dv" DocValues, collect into ordinal array.
*/
const METHOD_DV = 'dv';
/**
* Facet method "uif" UnInvertedField, collect into ordinal array.
*/
const METHOD_UIF = 'uif';
/**
* Facet method "dvhash" DocValues, collect into hash - improves efficiency over high cardinality fields.
*/
const METHOD_DVHASH = 'dvhash';
/**
* Facet method "enum" TermsEnum then intersect DocSet (stream-able).
*/
const METHOD_ENUM = 'enum';
/**
* Facet method "stream" Presently equivalent to "enum".
*/
const METHOD_STREAM = 'stream';
/**
* Facet method "smart" Pick the best method for the field type (this is the default).
*/
const METHOD_SMART = 'smart';
/**
* Get the facet type.
*
* @return string
*/
public function getType()
{
return FacetSetInterface::JSON_FACET_TERMS;
}
/**
* Set the refine parameter.
*
* If true, turns on distributed facet refining. This uses a second phase to retrieve selected stats from shards so
* that every shard contributes to every returned bucket in this facet and any sub-facets. This makes stats for
* returned buckets exact.
*
* @param bool $refine
*
* @return self Provides fluent interface
*/
public function setRefine(bool $refine)
{
return $this->setOption('refine', $refine);
}
/**
* Get the refine parameter.
*
* @return bool
*/
public function getRefine()
{
return $this->getOption('refine');
}
/**
* Set the overrequest parameter.
*
* Number of buckets beyond the limit to request internally during distributed search. -1 means default.
*
* @param int $overrequest
*
* @return self Provides fluent interface
*/
public function setOverRequest(int $overrequest)
{
return $this->setOption('overrequest', $overrequest);
}
/**
* Get the refine parameter.
*
* @return int
*/
public function getOverRequest()
{
return $this->getOption('overrequest');
}
/**
* Set the numBuckets parameter.
*
* A boolean. If true, adds “numBuckets” to the response, an integer representing the number of buckets for the
* facet (as opposed to the number of buckets returned). Defaults to false.
*
* @param bool $numBuckets
*
* @return self Provides fluent interface
*/
public function setNumBuckets(bool $numBuckets)
{
return $this->setOption('numBuckets', $numBuckets);
}
/**
* Get the numBuckets parameter.
*
* @return bool
*/
public function getNumBuckets()
{
return $this->getOption('numBuckets');
}
/**
* Set the allBuckets parameter.
*
* A boolean. If true, adds an “allBuckets” bucket to the response, representing the union of all of the buckets.
* For multi-valued fields, this is different than a bucket for all of the documents in the domain since a single
* document can belong to multiple buckets. Defaults to false.
*
* @param bool $allBuckets
*
* @return self Provides fluent interface
*/
public function setAllBuckets(bool $allBuckets)
{
return $this->setOption('allBuckets', $allBuckets);
}
/**
* Get the allBuckets parameter.
*
* @return bool
*/
public function getAllBuckets()
{
return $this->getOption('allBuckets');
}
}
......@@ -3,7 +3,7 @@
namespace Solarium\Component\Facet;
use Solarium\Component\Facet\Query as FacetQuery;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
use Solarium\Exception\InvalidArgumentException;
/**
......@@ -14,6 +14,13 @@ use Solarium\Exception\InvalidArgumentException;
*/
class MultiQuery extends AbstractFacet
{
use ExcludeTagsTrait {
init as excludeTagsInit;
addExclude as excludeTagsAddExclude;
removeExclude as excludeTagsRemoveExclude;
clearExcludes as excludeTagsClearExcludes;
}
/**
* Facet query objects.
*
......@@ -28,7 +35,7 @@ class MultiQuery extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_MULTIQUERY;
return FacetSetInterface::FACET_MULTIQUERY;
}
/**
......@@ -207,7 +214,7 @@ class MultiQuery extends AbstractFacet
$facetQuery->addExclude($tag);
}
return parent::addExclude($tag);
return $this->excludeTagsAddExclude($tag);
}
/**
......@@ -229,7 +236,7 @@ class MultiQuery extends AbstractFacet
$facetQuery->removeExclude($exclude);
}
return parent::removeExclude($exclude);
return $this->excludeTagsRemoveExclude($exclude);
}
/**
......@@ -249,7 +256,7 @@ class MultiQuery extends AbstractFacet
$facetQuery->clearExcludes();
}
return parent::clearExcludes();
return $this->excludeTagsClearExcludes();
}
/**
......@@ -260,7 +267,7 @@ class MultiQuery extends AbstractFacet
*/
protected function init()
{
parent::init();
$this->excludeTagsInit();
foreach ($this->options as $name => $value) {
switch ($name) {
......
......@@ -2,7 +2,7 @@
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
/**
* Facet pivot.
......@@ -11,6 +11,8 @@ use Solarium\Component\FacetSet;
*/
class Pivot extends AbstractFacet
{
use ExcludeTagsTrait;
/**
* Fields to use.
*
......@@ -32,7 +34,7 @@ class Pivot extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_PIVOT;
return FacetSetInterface::FACET_PIVOT;
}
/**
......
......@@ -2,7 +2,7 @@
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
use Solarium\Core\Query\Helper;
/**
......@@ -12,6 +12,8 @@ use Solarium\Core\Query\Helper;
*/
class Query extends AbstractFacet
{
use ExcludeTagsTrait;
/**
* Default options.
*
......@@ -28,7 +30,7 @@ class Query extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_QUERY;
return FacetSetInterface::FACET_QUERY;
}
/**
......
......@@ -2,64 +2,18 @@
namespace Solarium\Component\Facet;
use Solarium\Component\FacetSet;
use Solarium\Component\FacetSetInterface;
/**
* Facet range.
*
* @see http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range
*/
class Range extends AbstractFacet
class Range extends AbstractRange implements ExcludeTagsInterface
{
/**
* Value for the 'other' option.
*/
const OTHER_BEFORE = 'before';
/**
* Value for the 'other' option.
*/
const OTHER_AFTER = 'after';
/**
* Value for the 'other' option.
*/
const OTHER_BETWEEN = 'between';
/**
* Value for the 'other' option.
*/
const OTHER_ALL = 'all';
/**
* Value for the 'other' option.
*/
const OTHER_NONE = 'none';
/**
* Value for the 'include' option.
*/
const INCLUDE_LOWER = 'lower';
/**
* Value for the 'include' option.
*/
const INCLUDE_UPPER = 'upper';
/**
* Value for the 'include' option.
*/
const INCLUDE_EDGE = 'edge';
/**
* Value for the 'include' option.
*/
const INCLUDE_OUTER = 'outer';
/**
* Value for the 'include' option.
*/
const INCLUDE_ALL = 'all';
use ExcludeTagsTrait {
init as excludeTagsInit;
}
/**
* Get the facet type.
......@@ -68,194 +22,7 @@ class Range extends AbstractFacet
*/
public function getType()
{
return FacetSet::FACET_RANGE;
}
/**
* Set the field name.
*
* @param string $field
*
* @return self Provides fluent interface
*/
public function setField($field)
{
return $this->setOption('field', $field);
}
/**
* Get the field name.
*
* @return string
*/
public function getField()
{
return $this->getOption('field');
}
/**
* Set the lower bound of the range.
*
* @param string $start
*
* @return self Provides fluent interface
*/
public function setStart($start)
{
return $this->setOption('start', $start);
}
/**
* Get the lower bound of the range.
*
* @return string
*/
public function getStart()
{
return $this->getOption('start');
}
/**
* Set the upper bound of the range.
*
* @param string $end
*
* @return self Provides fluent interface
*/
public function setEnd($end)
{
return $this->setOption('end', $end);
}
/**
* Get the upper bound of the range.
*
* @return string
*/
public function getEnd()
{
return $this->getOption('end');
}
/**
* Set range gap.
*
* The size of each range expressed as a value to be added to the lower bound
*
* @param string $gap
*
* @return self Provides fluent interface
*/
public function setGap($gap)
{
return $this->setOption('gap', $gap);
}
/**
* Get range gap.
*
* The size of each range expressed as a value to be added to the lower bound
*
* @return string
*/
public function getGap()
{
return $this->getOption('gap');
}
/**
* Set hardend option.
*
* A Boolean parameter instructing Solr what to do in the event that facet.range.gap
* does not divide evenly between facet.range.start and facet.range.end
*
* @param bool $hardend
*
* @return self Provides fluent interface
*/
public function setHardend($hardend)
{
return $this->setOption('hardend', $hardend);
}
/**
* Get hardend option.
*
* @return bool
*/
public function getHardend()
{
return $this->getOption('hardend');
}
/**
* Set other counts.
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $other
*
* @return self Provides fluent interface
*/
public function setOther($other)
{
if (is_string($other)) {
$other = explode(',', $other);
$other = array_map('trim', $other);
}
return $this->setOption('other', $other);
}
/**
* Get other counts.
*
* @return array
*/
public function getOther()
{
$other = $this->getOption('other');
if (null === $other) {
$other = [];
}
return $other;
}
/**
* Set include option.
*
* Use one of the constants as value.
* If you want to use multiple values supply an array or comma separated string
*
* @param string|array $include
*
* @return self Provides fluent interface
*/
public function setInclude($include)
{
if (is_string($include)) {
$include = explode(',', $include);
$include = array_map('trim', $include);
}
return $this->setOption('include', $include);
}
/**
* Get include option.
*
* @return array
*/
public function getInclude()
{
$include = $this->getOption('include');
if (null === $include) {
$include = [];
}
return $include;
return FacetSetInterface::FACET_RANGE;
}
/**
......@@ -289,16 +56,6 @@ class Range extends AbstractFacet
protected function init()
{
parent::init();
foreach ($this->options as $name => $value) {
switch ($name) {
case 'include':
$this->setInclude($value);
break;
case 'other':
$this->setOther($value);
break;
}
}
$this->excludeTagsInit();
}
}
......@@ -2,48 +2,16 @@
namespace Solarium\Component;
use Solarium\Component\Facet\AbstractFacet;
use Solarium\Component\Facet\FacetInterface;
use Solarium\Component\RequestBuilder\FacetSet as RequestBuilder;
use Solarium\Component\ResponseParser\FacetSet as ResponseParser;
use Solarium\Exception\InvalidArgumentException;
use Solarium\Exception\OutOfBoundsException;
/**
* MoreLikeThis component.
*
* @see http://wiki.apache.org/solr/MoreLikeThis
* FacetSet component.
*/
class FacetSet extends AbstractComponent
class FacetSet extends AbstractComponent implements FacetSetInterface
{
/**
* Facet type field.
*/
const FACET_FIELD = 'field';
/**
* Facet type query.
*/
const FACET_QUERY = 'query';
/**
* Facet type multiquery.
*/
const FACET_MULTIQUERY = 'multiquery';
/**
* Facet type range.
*/
const FACET_RANGE = 'range';
/**
* Facet type pivot.
*/
const FACET_PIVOT = 'pivot';
/**
* Facet type interval.
*/
const FACET_INTERVAL = 'interval';
use FacetSetTrait;
/**
* Facet type mapping.
......@@ -51,25 +19,21 @@ class FacetSet extends AbstractComponent
* @var array
*/
protected $facetTypes = [
self::FACET_FIELD => 'Solarium\Component\Facet\Field',
self::FACET_QUERY => 'Solarium\Component\Facet\Query',
self::FACET_MULTIQUERY => 'Solarium\Component\Facet\MultiQuery',
self::FACET_RANGE => 'Solarium\Component\Facet\Range',
self::FACET_PIVOT => 'Solarium\Component\Facet\Pivot',
self::FACET_INTERVAL => 'Solarium\Component\Facet\Interval',
FacetSetInterface::FACET_FIELD => 'Solarium\Component\Facet\Field',
FacetSetInterface::FACET_QUERY => 'Solarium\Component\Facet\Query',
FacetSetInterface::FACET_MULTIQUERY => 'Solarium\Component\Facet\MultiQuery',
FacetSetInterface::FACET_RANGE => 'Solarium\Component\Facet\Range',
FacetSetInterface::FACET_PIVOT => 'Solarium\Component\Facet\Pivot',
FacetSetInterface::FACET_INTERVAL => 'Solarium\Component\Facet\Interval',
FacetSetInterface::JSON_FACET_TERMS => 'Solarium\Component\Facet\JsonTerms',
FacetSetInterface::JSON_FACET_QUERY => 'Solarium\Component\Facet\JsonQuery',
FacetSetInterface::JSON_FACET_RANGE => 'Solarium\Component\Facet\JsonRange',
];
/**
* Default options.
*
* @var array
*/
protected $options = [];
/**
* Facets.
*
* @var AbstractFacet[]
* @var FacetInterface[]
*/
protected $facets = [];
......@@ -310,174 +274,6 @@ class FacetSet extends AbstractComponent
return $this->getOption('missing');
}
/**
* Add a facet.
*
*
* @param \Solarium\Component\Facet\AbstractFacet|array $facet
*
* @throws InvalidArgumentException
*
* @return self Provides fluent interface
*/
public function addFacet($facet)
{
if (is_array($facet)) {
$facet = $this->createFacet($facet['type'], $facet, false);
}
$key = $facet->getKey();
if (0 === strlen($key)) {
throw new InvalidArgumentException('A facet must have a key value');
}
//double add calls for the same facet are ignored, but non-unique keys cause an exception
if (array_key_exists($key, $this->facets) && $this->facets[$key] !== $facet) {
throw new InvalidArgumentException('A facet must have a unique key value within a query');
}
$this->facets[$key] = $facet;
return $this;
}
/**
* Add multiple facets.
*
* @param array $facets
*
* @return self Provides fluent interface
*/
public function addFacets(array $facets)
{
foreach ($facets as $key => $facet) {
// in case of a config array: add key to config
if (is_array($facet) && !isset($facet['key'])) {
$facet['key'] = $key;
}
$this->addFacet($facet);
}
return $this;
}
/**
* Get a facet.
*
* @param string $key
*
* @return string
*/
public function getFacet($key)
{
if (isset($this->facets[$key])) {
return $this->facets[$key];
}
}
/**
* Get all facets.
*
* @return AbstractFacet[]
*/
public function getFacets()
{
return $this->facets;
}
/**
* Remove a single facet.
*
* You can remove a facet by passing its key or the facet instance
*
* @param string|\Solarium\Component\Facet\AbstractFacet $facet
*
* @return self Provides fluent interface
*/
public function removeFacet($facet)
{
if (is_object($facet)) {
$facet = $facet->getKey();
}
if (isset($this->facets[$facet])) {
unset($this->facets[$facet]);
}
return $this;
}
/**
* Remove all facets.
*
* @return self Provides fluent interface
*/
public function clearFacets()
{
$this->facets = [];
return $this;
}
/**
* Set multiple facets.
*
* This overwrites any existing facets
*
* @param array $facets
*/
public function setFacets($facets)
{
$this->clearFacets();
$this->addFacets($facets);
}
/**
* Create a facet instance.
*
* If you supply a string as the first arguments ($options) it will be used as the key for the facet
* and it will be added to this query.
* If you supply an options array/object that contains a key the facet will also be added to the query.
*
* When no key is supplied the facet cannot be added, in that case you will need to add it manually
* after setting the key, by using the addFacet method.
*
*
* @param string $type
* @param array|object|null $options
* @param bool $add
*
* @throws OutOfBoundsException
*
* @return \Solarium\Component\Facet\AbstractFacet
*/
public function createFacet($type, $options = null, $add = true)
{
$type = strtolower($type);
if (!isset($this->facetTypes[$type])) {
throw new OutOfBoundsException('Facettype unknown: '.$type);
}
$class = $this->facetTypes[$type];
if (is_string($options)) {
/** @var \Solarium\Component\Facet\Facet $facet */
$facet = new $class();
$facet->setKey($options);
} else {
$facet = new $class($options);
}
if ($add && null !== $facet->getKey()) {
$this->addFacet($facet);
}
return $facet;
}
/**
* Get a facet field instance.
*
......@@ -488,7 +284,7 @@ class FacetSet extends AbstractComponent
*/
public function createFacetField($options = null, $add = true)
{
return $this->createFacet(self::FACET_FIELD, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_FIELD, $options, $add);
}
/**
......@@ -501,7 +297,7 @@ class FacetSet extends AbstractComponent
*/
public function createFacetQuery($options = null, $add = true)
{
return $this->createFacet(self::FACET_QUERY, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_QUERY, $options, $add);
}
/**
......@@ -514,7 +310,7 @@ class FacetSet extends AbstractComponent
*/
public function createFacetMultiQuery($options = null, $add = true)
{
return $this->createFacet(self::FACET_MULTIQUERY, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_MULTIQUERY, $options, $add);
}
/**
......@@ -527,7 +323,7 @@ class FacetSet extends AbstractComponent
*/
public function createFacetRange($options = null, $add = true)
{
return $this->createFacet(self::FACET_RANGE, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_RANGE, $options, $add);
}
/**
......@@ -540,7 +336,7 @@ class FacetSet extends AbstractComponent
*/
public function createFacetPivot($options = null, $add = true)
{
return $this->createFacet(self::FACET_PIVOT, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_PIVOT, $options, $add);
}
/**
......@@ -553,25 +349,45 @@ class FacetSet extends AbstractComponent
*/
public function createFacetInterval($options = null, $add = true)
{
return $this->createFacet(self::FACET_INTERVAL, $options, $add);
return $this->createFacet(FacetSetInterface::FACET_INTERVAL, $options, $add);
}
/**
* Initialize options.
* Get a json facet terms instance.
*
* @param mixed $options
* @param bool $add
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
* @return \Solarium\Component\Facet\JsonTerms
*/
protected function init()
public function createJsonFacetTerms($options = null, $add = true)
{
if (isset($this->options['facet'])) {
foreach ($this->options['facet'] as $key => $config) {
if (!isset($config['key'])) {
$config['key'] = $key;
return $this->createFacet(FacetSetInterface::JSON_FACET_TERMS, $options, $add);
}
$this->addFacet($config);
}
/**
* Get a json facet query instance.
*
* @param mixed $options
* @param bool $add
*
* @return \Solarium\Component\Facet\JsonQuery
*/
public function createJsonFacetQuery($options = null, $add = true)
{
return $this->createFacet(FacetSetInterface::JSON_FACET_QUERY, $options, $add);
}
/**
* Get a json facet range instance.
*
* @param mixed $options
* @param bool $add
*
* @return \Solarium\Component\Facet\JsonRange
*/
public function createJsonFacetRange($options = null, $add = true)
{
return $this->createFacet(FacetSetInterface::JSON_FACET_RANGE, $options, $add);
}
}
<?php
namespace Solarium\Component;
use Solarium\Component\Facet\FacetInterface;
use Solarium\Exception\InvalidArgumentException;
use Solarium\Exception\OutOfBoundsException;
/**
* FacetSet interface.
*/
interface FacetSetInterface
{
/**
* Facet type field.
*/
const FACET_FIELD = 'field';
/**
* Facet type query.
*/
const FACET_QUERY = 'query';
/**
* Facet type multiquery.
*/
const FACET_MULTIQUERY = 'multiquery';
/**
* Facet type range.
*/
const FACET_RANGE = 'range';
/**
* Facet type pivot.
*/
const FACET_PIVOT = 'pivot';
/**
* Facet type interval.
*/
const FACET_INTERVAL = 'interval';
/**
* Facet type field.
*/
const JSON_FACET_TERMS = 'json_terms';
/**
* Facet type query.
*/
const JSON_FACET_QUERY = 'json_query';
/**
* Facet type range.
*/
const JSON_FACET_RANGE = 'json_range';
/**
* Facet type range.
*/
const JSON_FACET_AGGREGATION = 'json_aggregation';
/**
* Add a facet.
*
* @param FacetInterface|array $facet
*
* @throws InvalidArgumentException
*
* @return \Solarium\Component\FacetSet
*/
public function addFacet($facet);
/**
* Add multiple facets.
*
* @param array $facets
*
* @return \Solarium\Component\FacetSet
*/
public function addFacets(array $facets);
/**
* Get a facet.
*
* @param string $key
*
* @return FacetInterface
*/
public function getFacet($key);
/**
* Get all facets.
*
* @return FacetInterface[]
*/
public function getFacets();
/**
* Remove a single facet.
*
* You can remove a facet by passing its key or the facet instance
*
* @param string|FacetInterface $facet
*
* @return \Solarium\Component\FacetSet
*/
public function removeFacet($facet);
/**
* Remove all facets.
*
* @return \Solarium\Component\FacetSet
*/
public function clearFacets();
/**
* Set multiple facets.
*
* This overwrites any existing facets
*
* @param FacetInterface[] $facets
*/
public function setFacets($facets);
/**
* Create a facet instance.
*
* If you supply a string as the first arguments ($options) it will be used as the key for the facet
* and it will be added to this query.
* If you supply an options array/object that contains a key the facet will also be added to the query.
*
* When no key is supplied the facet cannot be added, in that case you will need to add it manually
* after setting the key, by using the addFacet method.
*
*
* @param string $type
* @param array|object|null $options
* @param bool $add
*
* @throws OutOfBoundsException
*
* @return FacetInterface
*/
public function createFacet(string $type, $options = null, bool $add = true);
}
<?php
namespace Solarium\Component;
use Solarium\Component\Facet\FacetInterface;
use Solarium\Exception\InvalidArgumentException;
use Solarium\Exception\OutOfBoundsException;
/**
* FacetSet trait.
*/
trait FacetSetTrait
{
/**
* Facets.
*
* @var FacetInterface[]
*/
protected $facets = [];
/**
* Add a facet.
*
*
* @param \Solarium\Component\Facet\FacetInterface|array $facet
*
* @throws InvalidArgumentException
*
* @return self Provides fluent interface
*/
public function addFacet($facet)
{
if (is_array($facet)) {
$facet = $this->createFacet($facet['type'], $facet, false);
}
$key = $facet->getKey();
if (0 === strlen($key)) {
throw new InvalidArgumentException('A facet must have a key value');
}
//double add calls for the same facet are ignored, but non-unique keys cause an exception
if (array_key_exists($key, $this->facets) && $this->facets[$key] !== $facet) {
throw new InvalidArgumentException('A facet must have a unique key value within a query');
}
$this->facets[$key] = $facet;
return $this;
}
/**
* Add multiple facets.
*
* @param array $facets
*
* @return self Provides fluent interface
*/
public function addFacets(array $facets)
{
foreach ($facets as $key => $facet) {
// in case of a config array: add key to config
if (is_array($facet) && !isset($facet['key'])) {
$facet['key'] = $key;
}
$this->addFacet($facet);
}
return $this;
}
/**
* Get a facet.
*
* @param string $key
*
* @return FacetInterface
*/
public function getFacet($key)
{
if (isset($this->facets[$key])) {
return $this->facets[$key];
}
}
/**
* Get all facets.
*
* @return FacetInterface[]
*/
public function getFacets()
{
return $this->facets;
}
/**
* Remove a single facet.
*
* You can remove a facet by passing its key or the facet instance
*
* @param string|\Solarium\Component\Facet\FacetInterface $facet
*
* @return self Provides fluent interface
*/
public function removeFacet($facet)
{
if (is_object($facet)) {
$facet = $facet->getKey();
}
if (isset($this->facets[$facet])) {
unset($this->facets[$facet]);
}
return $this;
}
/**
* Remove all facets.
*
* @return self Provides fluent interface
*/
public function clearFacets()
{
$this->facets = [];
return $this;
}
/**
* Set multiple facets.
*
* This overwrites any existing facets
*
* @param array $facets
*/
public function setFacets($facets)
{
$this->clearFacets();
$this->addFacets($facets);
}
/**
* Create a facet instance.
*
* If you supply a string as the first arguments ($options) it will be used as the key for the facet
* and it will be added to this query.
* If you supply an options array/object that contains a key the facet will also be added to the query.
*
* When no key is supplied the facet cannot be added, in that case you will need to add it manually
* after setting the key, by using the addFacet method.
*
*
* @param string $type
* @param array|object|null $options
* @param bool $add
*
* @throws OutOfBoundsException
*
* @return \Solarium\Component\Facet\FacetInterface
*/
public function createFacet(string $type, $options = null, bool $add = true)
{
$type = strtolower($type);
if (!isset($this->facetTypes[$type])) {
throw new OutOfBoundsException('Facettype unknown: '.$type);
}
$class = $this->facetTypes[$type];
if (is_string($options)) {
/** @var FacetInterface $facet */
$facet = new $class();
$facet->setKey($options);
} else {
$facet = new $class($options);
}
if ($add && null !== $facet->getKey()) {
$this->addFacet($facet);
}
return $facet;
}
/**
* Initialize options.
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
*/
protected function init()
{
if (isset($this->options['facet'])) {
foreach ($this->options['facet'] as $key => $config) {
if (!isset($config['key'])) {
$config['key'] = $key;
}
$this->addFacet($config);
}
}
}
}
......@@ -4,11 +4,13 @@ namespace Solarium\Component\RequestBuilder;
use Solarium\Component\Facet\Field as FacetField;
use Solarium\Component\Facet\Interval as FacetInterval;
use Solarium\Component\Facet\JsonFacetInterface;
use Solarium\Component\Facet\MultiQuery as FacetMultiQuery;
use Solarium\Component\Facet\Pivot as FacetPivot;
use Solarium\Component\Facet\Query as FacetQuery;
use Solarium\Component\Facet\Range as FacetRange;
use Solarium\Component\FacetSet as FacetsetComponent;
use Solarium\Component\FacetSetInterface;
use Solarium\Core\Client\Request;
use Solarium\Exception\UnexpectedValueException;
use Solarium\QueryType\Select\RequestBuilder;
......@@ -33,42 +35,69 @@ class FacetSet extends RequestBuilder implements ComponentRequestBuilderInterfac
{
$facets = $component->getFacets();
if (0 !== count($facets)) {
// enable faceting
$request->addParam('facet', 'true');
// global facet params
$request->addParam('facet.sort', $component->getSort());
$request->addParam('facet.prefix', $component->getPrefix());
$request->addParam('facet.contains', $component->getContains());
$request->addParam('facet.contains.ignoreCase', null === ($ignoreCase = $component->getContainsIgnoreCase()) ? null : ($ignoreCase ? 'true' : 'false'));
$request->addParam('facet.missing', $component->getMissing());
$request->addParam('facet.mincount', $component->getMinCount());
$request->addParam('facet.limit', $component->getLimit());
foreach ($facets as $facet) {
$non_json = false;
$json_facets = [];
foreach ($facets as $key => $facet) {
switch ($facet->getType()) {
case FacetsetComponent::FACET_FIELD:
case FacetSetInterface::FACET_FIELD:
/* @var FacetField $facet */
$this->addFacetField($request, $facet);
$non_json = true;
break;
case FacetsetComponent::FACET_QUERY:
case FacetSetInterface::FACET_QUERY:
/* @var FacetQuery $facet */
$this->addFacetQuery($request, $facet);
$non_json = true;
break;
case FacetsetComponent::FACET_MULTIQUERY:
case FacetSetInterface::FACET_MULTIQUERY:
/* @var FacetMultiQuery $facet */
$this->addFacetMultiQuery($request, $facet);
$non_json = true;
break;
case FacetsetComponent::FACET_RANGE:
case FacetSetInterface::FACET_RANGE:
/* @var FacetRange $facet */
$this->addFacetRange($request, $facet);
$non_json = true;
break;
case FacetsetComponent::FACET_PIVOT:
case FacetSetInterface::FACET_PIVOT:
/* @var FacetPivot $facet */
$this->addFacetPivot($request, $facet);
$non_json = true;
break;
case FacetsetComponent::FACET_INTERVAL:
case FacetSetInterface::FACET_INTERVAL:
/* @var FacetInterval $facet */
$this->addFacetInterval($request, $facet);
$non_json = true;
break;
case FacetSetInterface::JSON_FACET_TERMS:
case FacetSetInterface::JSON_FACET_QUERY:
case FacetSetInterface::JSON_FACET_RANGE:
case FacetSetInterface::JSON_FACET_AGGREGATION:
/* @var JsonFacetInterface $facet */
$json_facets[$key] = $facet->serialize();
break;
default:
throw new UnexpectedValueException('Unknown facet type');
}
}
if ($non_json) {
// enable non-json faceting
$request->addParam('facet', 'true');
// global facet params
$request->addParam('facet.sort', $component->getSort());
$request->addParam('facet.prefix', $component->getPrefix());
$request->addParam('facet.contains', $component->getContains());
$request->addParam('facet.contains.ignoreCase', null === ($ignoreCase = $component->getContainsIgnoreCase()) ? null : ($ignoreCase ? 'true' : 'false'));
$request->addParam('facet.missing', $component->getMissing());
$request->addParam('facet.mincount', $component->getMinCount());
$request->addParam('facet.limit', $component->getLimit());
}
if ($json_facets) {
$request->addParam('json.facet', json_encode($json_facets));
}
}
return $request;
......
......@@ -8,6 +8,10 @@ use Solarium\Component\Facet\Pivot as QueryFacetPivot;
use Solarium\Component\Facet\Query as QueryFacetQuery;
use Solarium\Component\Facet\Range as QueryFacetRange;
use Solarium\Component\FacetSet as QueryFacetSet;
use Solarium\Component\FacetSetInterface;
use Solarium\Component\Result\Facet\Aggregation;
use Solarium\Component\Result\Facet\Bucket;
use Solarium\Component\Result\Facet\Buckets;
use Solarium\Component\Result\Facet\Field as ResultFacetField;
use Solarium\Component\Result\Facet\Interval as ResultFacetInterval;
use Solarium\Component\Result\Facet\MultiQuery as ResultFacetMultiQuery;
......@@ -73,27 +77,33 @@ class FacetSet extends ResponseParserAbstract implements ComponentParserInterfac
$facets = [];
foreach ($facetSet->getFacets() as $key => $facet) {
$result = null;
switch ($facet->getType()) {
case QueryFacetSet::FACET_FIELD:
case FacetSetInterface::FACET_FIELD:
$result = $this->facetField($query, $facet, $data);
break;
case QueryFacetSet::FACET_QUERY:
case FacetSetInterface::FACET_QUERY:
$result = $this->facetQuery($facet, $data);
break;
case QueryFacetSet::FACET_MULTIQUERY:
case FacetSetInterface::FACET_MULTIQUERY:
$result = $this->facetMultiQuery($facet, $data);
break;
case QueryFacetSet::FACET_RANGE:
case FacetSetInterface::FACET_RANGE:
$result = $this->facetRange($query, $facet, $data);
break;
case QueryFacetSet::FACET_PIVOT:
case FacetSetInterface::FACET_PIVOT:
$result = $this->facetPivot($query, $facet, $data);
break;
case QueryFacetSet::FACET_INTERVAL:
case FacetSetInterface::FACET_INTERVAL:
$result = $this->facetInterval($query, $facet, $data);
break;
case FacetSetInterface::JSON_FACET_AGGREGATION:
case FacetSetInterface::JSON_FACET_QUERY:
case FacetSetInterface::JSON_FACET_RANGE:
case FacetSetInterface::JSON_FACET_TERMS:
break;
default:
throw new RuntimeException('Unknown facet type');
throw new RuntimeException(sprintf('Unknown facet type %s', $facet->getType()));
}
if (null !== $result) {
......@@ -101,9 +111,46 @@ class FacetSet extends ResponseParserAbstract implements ComponentParserInterfac
}
}
if (!empty($data['facets'])) {
$facets += $this->parseJsonFacetSet($data['facets']);
}
return $this->createFacetSet($facets);
}
/**
* Parse JSON facets.
*
* @param array $facets
*
* @return array
*/
protected function parseJsonFacetSet($facets)
{
$buckets_and_aggregations = [];
foreach ($facets as $key => $values) {
if (is_array($values)) {
if (isset($values['buckets'])) {
$buckets = [];
// Parse buckets.
foreach ($values['buckets'] as $bucket) {
$val = $bucket['val'];
$count = $bucket['count'];
unset($bucket['val']);
unset($bucket['count']);
$buckets[] = new Bucket($val, $count, new ResultFacetSet($this->parseJsonFacetSet($bucket)));
}
$buckets_and_aggregations[$key] = new Buckets($buckets);
} else {
$buckets_and_aggregations[$key] = new ResultFacetSet($this->parseJsonFacetSet($values));
}
} else {
$buckets_and_aggregations[$key] = new Aggregation($values);
}
}
return $buckets_and_aggregations;
}
/**
* Create a facetset result object.
*
......
<?php
namespace Solarium\Component\Result\Facet;
/**
* Aggregation.
*/
class Aggregation
{
/**
* Value.
*
* @var float|int
*/
protected $value;
/**
* Constructor.
*
* @param float $value
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Get value.
*
* @return float|int
*/
public function getValue()
{
return $this->value;
}
}
<?php
namespace Solarium\Component\Result\Facet;
use Solarium\Component\Facet\FacetInterface;
use Solarium\Component\Result\FacetSet;
/**
* Select field facet result.
*
* A field facet will usually return a dataset of multiple rows, in each row a
* value and its count. You can access the values as an array using
* {@link getValues()} or iterate this object.
*/
class Bucket implements \IteratorAggregate, \Countable
{
/**
* Value.
*
* @var string
*/
protected $value;
/**
* Count.
*
* @var int
*/
protected $count;
/**
* Facet set.
*
* @var FacetSet
*/
protected $facetSet;
/**
* Bucket constructor.
*
* @param string $value
* @param int $count
* @param FacetSet $facets
*/
public function __construct(string $value, int $count, FacetSet $facets)
{
$this->value = $value;
$this->count = $count;
$this->facetSet = $facets;
}
/**
* Get the value.
*
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Get the count.
*
* @return int
*/
public function getCount()
{
return $this->count;
}
/**
* Get nested facets.
*
* @return FacetInterface[]
*/
public function getFacets()
{
return $this->facetSet->getFacets();
}
/**
* IteratorAggregate implementation.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->facetSet->getIterator();
}
/**
* Countable implementation.
*
* @return int the amount of nested facets
*/
public function count()
{
return count($this->facetSet->getFacets());
}
}
<?php
namespace Solarium\Component\Result\Facet;
/**
* Select field facet result.
*
* A field facet will usually return a dataset of multiple rows, in each row a
* value and its count. You can access the values as an array using
* {@link getValues()} or iterate this object.
*/
class Buckets implements \IteratorAggregate, \Countable
{
/**
* Value array.
*
* @var Bucket[]
*/
protected $buckets;
/**
* Constructor.
*
* @param Bucket[] $values
*/
public function __construct(array $buckets)
{
$this->buckets = $buckets;
}
/**
* Get all values.
*
* @return Bucket[]
*/
public function getBuckets()
{
return $this->buckets;
}
/**
* IteratorAggregate implementation.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->buckets);
}
/**
* Countable implementation.
*
* @return int
*/
public function count()
{
return count($this->buckets);
}
}
......@@ -2,6 +2,8 @@
namespace Solarium\Component\Result;
use Solarium\Component\Facet\FacetInterface;
/**
* Select component facetset result.
*/
......@@ -29,7 +31,7 @@ class FacetSet implements \IteratorAggregate, \Countable
*
* @param mixed $key
*
* @return mixed
* @return FacetInterface
*/
public function getFacet($key)
{
......@@ -41,7 +43,7 @@ class FacetSet implements \IteratorAggregate, \Countable
/**
* Get all results.
*
* @return array
* @return FacetInterface[]
*/
public function getFacets()
{
......
......@@ -3,8 +3,8 @@
namespace Solarium\QueryType\Select\Result;
use Solarium\Component\ComponentAwareQueryInterface;
use Solarium\Component\FacetSet;
use Solarium\Component\Result\Debug\Result as DebugResult;
use Solarium\Component\Result\FacetSet as FacetSetResult;
use Solarium\Component\Result\Grouping\Result as GroupingResult;
use Solarium\Component\Result\Highlighting\Highlighting;
use Solarium\Component\Result\MoreLikeThis\Result as MoreLikeThisResult;
......@@ -272,7 +272,7 @@ class Result extends BaseResult implements \IteratorAggregate, \Countable
*
* This is a convenience method that maps presets to getComponent
*
* @return FacetSet|null
* @return FacetSetResult|null
*/
public function getFacetSet()
{
......
......@@ -5,6 +5,10 @@ namespace Solarium\Tests\Component\RequestBuilder;
use PHPUnit\Framework\TestCase;
use Solarium\Component\Facet\Field as FacetField;
use Solarium\Component\Facet\Interval as FacetInterval;
use Solarium\Component\Facet\JsonAggregation;
use Solarium\Component\Facet\JsonQuery;
use Solarium\Component\Facet\JsonRange;
use Solarium\Component\Facet\JsonTerms;
use Solarium\Component\Facet\MultiQuery as FacetMultiQuery;
use Solarium\Component\Facet\Pivot as FacetPivot;
use Solarium\Component\Facet\Query as FacetQuery;
......@@ -12,6 +16,7 @@ use Solarium\Component\Facet\Range as FacetRange;
use Solarium\Component\FacetSet as Component;
use Solarium\Component\RequestBuilder\FacetSet as RequestBuilder;
use Solarium\Core\Client\Request;
use Solarium\Exception\InvalidArgumentException;
use Solarium\Exception\UnexpectedValueException;
class FacetSetTest extends TestCase
......@@ -60,7 +65,145 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.field={!key=f1}owner&facet.query={!key=f2}category:23&facet.query={!key=f4}category:40',
'?facet.field={!key=f1}owner&facet.query={!key=f2}category:23&facet.query={!key=f4}category:40&facet=true',
urldecode($request->getUri())
);
}
public function testBuildWithJsonFacets()
{
$this->component->addFacet(new JsonTerms(['key' => 'f1', 'field' => 'owner']));
$this->component->addFacet(new JsonQuery(['key' => 'f2', 'q' => 'category:23']));
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","type":"terms"},"f2":{"q":"category:23","type":"query"}}',
urldecode($request->getUri())
);
}
public function testBuildWithJsonFacetFilterQuery()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
$terms->setDomainFilterQuery('popularity:[5 TO 10]');
$this->component->addFacet($terms);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","domain":{"filter":"popularity:[5 TO 10]"},"type":"terms"}}',
urldecode($request->getUri())
);
}
public function testBuildWithJsonFacetFilterParams()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
$terms->addDomainFilterParameter('myparam1');
$terms->addDomainFilterParameter('myparam2');
$terms->addDomainFilterParameter('myparam3');
$terms->addDomainFilterParameter('myparam1');
$this->component->addFacet($terms);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","domain":{"filter":[{"param":"myparam1"},{"param":"myparam2"},{"param":"myparam3"}]},"type":"terms"}}',
urldecode($request->getUri())
);
}
public function testBuildWithJsonFacetFilterQueryAndParams()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
$terms->setDomainFilterQuery('popularity:[5 TO 10]');
$terms->addDomainFilterParameter('myparam1');
$terms->addDomainFilterParameter('myparam2');
$this->component->addFacet($terms);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","domain":{"filter":["popularity:[5 TO 10]",{"param":"myparam1"},{"param":"myparam2"}]},"type":"terms"}}',
urldecode($request->getUri())
);
}
public function testBuildWithJsonFacetFilterParamsAndQuery()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
$terms->addDomainFilterParameter('myparam1');
$terms->addDomainFilterParameter('myparam2');
$terms->setDomainFilterQuery('popularity:[5 TO 10]');
$this->component->addFacet($terms);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","domain":{"filter":[{"param":"myparam1"},{"param":"myparam2"},"popularity:[5 TO 10]"]},"type":"terms"}}',
urldecode($request->getUri())
);
}
public function testBuildWithFacetsAndJsonFacets()
{
$this->component->addFacet(new FacetField(['key' => 'f1', 'field' => 'owner']));
$this->component->addFacet(new JsonTerms(['key' => 'f2', 'field' => 'customer']));
$this->component->addFacet(new JsonQuery(['key' => 'f3', 'q' => 'category:23']));
$this->component->addFacet(
new FacetMultiQuery(['key' => 'f4', 'query' => ['f5' => ['query' => 'category:40']]])
);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet.field={!key=f1}owner&facet.query={!key=f5}category:40&facet=true&json.facet={"f2":{"field":"customer","type":"terms"},"f3":{"q":"category:23","type":"query"}}',
urldecode($request->getUri())
);
}
public function testBuildWithAggregationFacet()
{
$this->component->addFacet(new JsonAggregation(['key' => 'f1', 'function' => 'avg(mul(price,popularity))']));
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":"avg(mul(price,popularity))"}',
urldecode($request->getUri())
);
}
public function testBuildWithNestedFacets()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
// Only JSON facets could be nested.
$this->expectException(InvalidArgumentException::class);
$terms->addFacet(new FacetQuery(['key' => 'f2', 'q' => 'category:23']));
}
public function testBuildWithNestedJsonFacets()
{
$terms = new JsonTerms(['key' => 'f1', 'field' => 'owner']);
$query = new JsonQuery(['key' => 'f2', 'q' => 'category:23']);
$query->addFacet(new JsonAggregation(['key' => 'f1', 'function' => 'avg(mul(price,popularity))']));
$query->addFacet(new JsonAggregation(['key' => 'f2', 'function' => 'unique(popularity)']));
$terms->addFacet($query);
$this->component->addFacet($terms);
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"owner","type":"terms","facet":{"f2":{"q":"category:23","type":"query","facet":{"f1":"avg(mul(price,popularity))","f2":"unique(popularity)"}}}}}',
urldecode($request->getUri())
);
}
......@@ -84,7 +227,31 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.range={!key=f1}price&f.price.facet.range.start=1&f.price.facet.range.end=100&f.price.facet.range.gap=10&f.price.facet.mincount=123&f.price.facet.range.other=all&f.price.facet.range.include=outer',
'?facet.range={!key=f1}price&f.price.facet.range.start=1&f.price.facet.range.end=100&f.price.facet.range.gap=10&f.price.facet.mincount=123&f.price.facet.range.other=all&f.price.facet.range.include=outer&facet=true',
urldecode($request->getUri())
);
}
public function testBuildWithJsonRangeFacet()
{
$this->component->addFacet(new JsonRange(
[
'key' => 'f1',
'field' => 'price',
'start' => '1',
'end' => 100,
'gap' => 10,
'other' => 'all',
'include' => 'outer',
'mincount' => 123,
]
));
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertNull($request->getRawData());
$this->assertEquals(
'?json.facet={"f1":{"field":"price","start":"1","end":100,"gap":10,"other":["all"],"include":["outer"],"mincount":123,"type":"range"}}',
urldecode($request->getUri())
);
}
......@@ -107,8 +274,7 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.range={!key=f1}price&f.price.facet.range.start=1&f.price.facet.range.end=100'.
'&f.price.facet.range.gap=10',
'?facet.range={!key=f1}price&f.price.facet.range.start=1&f.price.facet.range.end=100&f.price.facet.range.gap=10&facet=true',
urldecode($request->getUri())
);
}
......@@ -131,8 +297,7 @@ class FacetSetTest extends TestCase
);
static::assertEquals(
'?facet=true&facet.missing=true&facet.limit=10&facet.field={!key=f1}owner&facet.query={!key=f2}category:23'.
'&facet.query={!key=f4}category:40',
'?facet.field={!key=f1}owner&facet.query={!key=f2}category:23&facet.query={!key=f4}category:40&facet=true&facet.missing=true&facet.limit=10',
urldecode($request->getUri())
);
}
......@@ -164,7 +329,7 @@ class FacetSetTest extends TestCase
);
$this->assertEquals(
'?facet=true&facet.pivot={!key=f1 ex=owner}cat,inStock&facet.pivot.mincount=123',
'?facet.pivot={!key=f1 ex=owner}cat,inStock&facet.pivot.mincount=123&facet=true',
urldecode($request->getUri())
);
}
......@@ -185,7 +350,7 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.pivot={!stats=piv1}cat,inStock',
'?facet.pivot={!stats=piv1}cat,inStock&facet=true',
urldecode($request->getUri())
);
}
......@@ -209,7 +374,7 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.contains=bar&facet.contains.ignoreCase=false&facet.field={!key=f1}owner&f.owner.facet.contains=foo&f.owner.facet.contains.ignoreCase=true',
'?facet.field={!key=f1}owner&f.owner.facet.contains=foo&f.owner.facet.contains.ignoreCase=true&facet=true&facet.contains=bar&facet.contains.ignoreCase=false',
urldecode($request->getUri())
);
}
......@@ -231,7 +396,7 @@ class FacetSetTest extends TestCase
$this->assertNull($request->getRawData());
$this->assertEquals(
'?facet=true&facet.interval={!key=f1}&f..facet.interval.set=int1&f..facet.interval.set={!key="one"}int2',
'?facet.interval={!key=f1}&f..facet.interval.set=int1&f..facet.interval.set={!key="one"}int2&facet=true',
urldecode($request->getUri())
);
}
......
......@@ -252,7 +252,7 @@ class FacetSetTest extends TestCase
public function testInvalidFacetType()
{
$facetStub = $this->createMock(Field::class);
$facetStub->expects($this->once())
$facetStub->expects($this->any())
->method('getType')
->will($this->returnValue('invalidfacettype'));
$facetStub->expects($this->any())
......@@ -264,4 +264,90 @@ class FacetSetTest extends TestCase
$this->expectException(RuntimeException::class);
$this->parser->parse($this->query, $this->facetSet, []);
}
public function testParseJsonFacet()
{
$data = [
'facets' => [
'top_genres' => [
'buckets' => [
[
'val' => 'Fantasy',
'count' => 5432,
'top_authors' => [
'buckets' => [
[
'val' => 'Mercedes Lackey',
'count' => 121,
],
[
'val' => 'Piers Anthony',
'count' => 98,
],
],
],
'highpop' => [
'count' => 876,
'publishers' => [
'buckets' => [
[
'val' => 'Bantam Books',
'count' => 346,
],
[
'val' => 'Tor',
'count' => 217,
],
],
],
],
],
[
'val' => 'Science Fiction',
'count' => 4188,
'top_authors' => [
'buckets' => [
[
'val' => 'Terry Pratchett',
'count' => 87,
],
],
],
'highpop' => [
'count' => 876,
'publishers' => [
'buckets' => [
[
'val' => 'Harper Collins',
'count' => 43,
],
],
],
],
],
],
],
],
];
$result = $this->parser->parse($this->query, $this->facetSet, $data);
$facets = $result->getFacets();
$this->assertEquals(['top_genres'], array_keys($facets));
$buckets = $facets['top_genres']->getBuckets();
$this->assertEquals(
'Fantasy',
$buckets[0]->getValue()
);
$this->assertEquals(
5432,
$buckets[0]->getCount()
);
$nested_facets = $buckets[0]->getFacets();
$this->assertEquals(['top_authors', 'highpop'], array_keys($nested_facets));
}
}
......@@ -4,11 +4,13 @@ namespace Solarium\Tests\QueryType\Select\Query\Component\Facet;
use PHPUnit\Framework\TestCase;
use Solarium\Component\Facet\AbstractFacet;
use Solarium\Component\Facet\ExcludeTagsTrait;
use Solarium\Component\Facet\FacetInterface;
class FacetTest extends TestCase
{
/**
* @var AbstractFacet
* @var FacetInterface
*/
protected $facet;
......@@ -72,6 +74,8 @@ class FacetTest extends TestCase
class TestFacet extends AbstractFacet
{
use ExcludeTagsTrait;
public function getType()
{
return 'test';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment