Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
php: [8.1, 8.2, 8.3, 8.4, 8.5]
solr: [7, 8, 9]
solr: [7, 8, 9, 10]
mode: [cloud, server]

name: PHP ${{ matrix.php }}, Solr ${{ matrix.solr }} ${{ matrix.mode }}
Expand Down Expand Up @@ -59,6 +59,14 @@ jobs:
ref: branch_9_10
path: lucene-solr

- name: Checkout solr 10.0
if: matrix.solr == 10
uses: actions/checkout@v4
with:
repository: apache/solr
ref: branch_10_0
path: lucene-solr

- name: Start Solr ${{ matrix.solr }} in ${{ matrix.mode }} mode
run: |
chmod -R a+w lucene-solr
Expand Down
16 changes: 9 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [7.0.0]
### Added
- Solr 10 support
- PHP 8.5 support
- Solarium\QueryType\Extract\Query::setStreamType()

Expand All @@ -15,13 +16,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Solarium\Plugin\MinimumScoreFilter\Document::__call() unpacks the $arguments array when forwarding a method call to the original document

### Changed
- Added `void` return type to `Solarium\Core\Plugin\PluginInterface::initPlugin()` method signature
- Added `void` return type to `Solarium\Core\Plugin\PluginInterface::deinitPlugin()` method signature
- Added `void` return type to `Solarium\Core\Plugin\AbstractPlugin::initPluginType()` method signature
- Changed return type of some Facets methods from `self`to `static`
- Replaced class property type hints with type declarations
- Added union type declarations to method signatures
- Solarium\Core\Query\Helper::formatDate() throws a `TypeError` instead of returning `false` if called with an incompatibly typed parameter
- Added `void` return type to `Solarium\Core\Plugin\PluginInterface::initPlugin()` method signature
- Added `void` return type to `Solarium\Core\Plugin\PluginInterface::deinitPlugin()` method signature
- Added `void` return type to `Solarium\Core\Plugin\AbstractPlugin::initPluginType()` method signature
- Changed return type of some Facets methods from `self` to `static`
- Replaced class property type hints with type declarations
- Added union type declarations to method signatures
- Solarium\Core\Query\Helper::formatDate() throws a `TypeError` instead of returning `false` if called with an incompatibly typed parameter
- Managed resources queries no longer work around SOLR-6853 by default. Set the 'useDoubleEncoding' option to `true` if this bug affects you.

### Removed
- Solarium\Component\Result\Stats\FacetValue::getFacets(), always returned `null`
Expand Down
5 changes: 5 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ do have one it must be contravariant.
Code that calls a method with parameters of an incompatible type will result in a `TypeError` where
they were previously coerced into a compatible type by PHP's type juggling.

Solarium 7 no longer works around [SOLR-6853](https://issues.apache.org/jira/browse/SOLR-6853) for
managed resources queries by default. The workaround is no longer necessary for Solr 10, but also
not forward compatible with this version. If this still affects you, set the 'useDoubleEncoding'
option to `true` on `ManagedResources\Query\Stopwords` or `ManagedResources\Query\Synonyms`.

### Pitfall when upgrading to 6.3.6

Using a config object is no longer supported. You have to convert it to an array before passing
Expand Down
18 changes: 18 additions & 0 deletions docs/queries/managedresources-query/managed-stopwords.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,24 @@ htmlFooter();

```

A note on percent-encoding reserved characters
----------------------------------------------

If the name of a stopword list or a stopword itself contains characters that are not
[unreserved characters as defined by RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3),
they must be percent-encoded when appearing as part of a URL. Solarium handles this for you.

However, if you're using a Solr version prior to Solr 10 and list names or stopwords
that contain [reserved characters](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2),
you will be affected by [SOLR-6853](https://issues.apache.org/jira/browse/SOLR-6853). You can
instruct Solarium to double up on the percent-encoding as a workaround.

```php
$query = $client->createManagedStopwords(['useDoubleEncoding' => true]);
```

Keep in mind that Solr may not be able to handle some of these reserved characters regardless.

A note on `HEAD` requests
-------------------------

Expand Down
18 changes: 18 additions & 0 deletions docs/queries/managedresources-query/managed-synonyms.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,24 @@ htmlFooter();

```

A note on percent-encoding reserved characters
----------------------------------------------

If the name of a synonym map or a synonym itself contains characters that are not
[unreserved characters as defined by RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3),
they must be percent-encoded when appearing as part of a URL. Solarium handles this for you.

However, if you're using a Solr version prior to Solr 10 and map names or synonyms
that contain [reserved characters](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2),
you will be affected by [SOLR-6853](https://issues.apache.org/jira/browse/SOLR-6853). You can
instruct Solarium to double up on the percent-encoding as a workaround.

```php
$query = $client->createManagedSynonyms(['useDoubleEncoding' => true]);
```

Keep in mind that Solr may not be able to handle some of these reserved characters regardless.

A note on `HEAD` requests
-------------------------

Expand Down
23 changes: 20 additions & 3 deletions examples/execute_all.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
$response = $client->coreAdmin($coreAdminQuery);
}

// @todo Figure out why this fails on Solr 9.
if (9 !== $solrVersion) {
// @todo Figure out why this fails starting with Solr 9.
if (9 > $solrVersion) {
// check if /mlt handler exists (it will in the github worklow, but not when running this script on its own)
$query = $client->createApi([
'version' => Request::API_V1,
Expand All @@ -90,6 +90,23 @@
}
}

// Solr 10 no longer comes with LocalTikaExtractionBackend, the github workflow runs a remote Tika Server instead
if (10 <= $solrVersion) {
$query = $client->createApi([
'version' => Request::API_V1,
'handler' => $collection_or_core_name.'/config',
'method' => Request::METHOD_POST,
'rawdata' => json_encode([
'update-requesthandler' => [
'name' => '/update/extract',
'class' => 'solr.extraction.ExtractingRequestHandler',
'tikaserver.url' => 'http://tika:9998',
],
]),
]);
$client->execute($query);
}

// check if attr_* dynamic field definition exists (it was removed from the techproducts configset in Solr 9.1)
try {
$query = $client->createApi([
Expand Down Expand Up @@ -172,7 +189,7 @@
// examples that can't be run against this Solr version
$skipForSolrVersion = [];

if (9 === $solrVersion) {
if (9 <= $solrVersion) {
$skipForSolrVersion[] = '2.3.1-mlt-query.php';
$skipForSolrVersion[] = '2.3.2-mlt-stream.php';
}
Expand Down
28 changes: 28 additions & 0 deletions src/QueryType/ManagedResources/Query/AbstractQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,32 @@ public function removeCommand(): self
* @return InitArgsInterface
*/
abstract public function createInitArgs(?array $initArgs = null): InitArgsInterface;

/**
* Percent-encode names and terms twice as a workaround for SOLR-6853?
*
* @return bool
*/
public function getUseDoubleEncoding(): bool
{
return $this->getOption('useDoubleEncoding') ?? false;
}

/**
* Percent-encode names and terms twice as a workaround for SOLR-6853?
*
* Solr versions prior to 10 required reserved characters to be doubly
* percent-encoded. Set this to true if your Solr version is affected by
* {@link https://issues.apache.org/jira/browse/SOLR-6853 SOLR-6853}.
*
* @param bool $useDoubleEncoding
*
* @return self Provides fluent interface
*/
public function setUseDoubleEncoding(bool $useDoubleEncoding): self
{
$this->setOption('useDoubleEncoding', $useDoubleEncoding);

return $this;
}
}
49 changes: 36 additions & 13 deletions src/QueryType/ManagedResources/RequestBuilder/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Solarium\Core\Query\AbstractRequestBuilder;
use Solarium\Core\Query\QueryInterface;
use Solarium\Exception\RuntimeException;
use Solarium\QueryType\ManagedResources\Query\AbstractCommand;
use Solarium\QueryType\ManagedResources\Query\AbstractQuery as BaseQuery;

/**
Expand All @@ -36,68 +35,92 @@ public function build(QueryInterface|BaseQuery $query): Request
throw new RuntimeException('Name of the resource is not set in the query.');
}

$name = rawurlencode($query->getName());
if ($query->getUseDoubleEncoding()) {
$name = rawurlencode($name);
}

$request = parent::build($query);
// reserved characters in a REST resource name need to be encoded twice to make it through the servlet (SOLR-6853)
$request->setHandler($query->getHandler().rawurlencode(rawurlencode($query->getName())));
$request->setHandler($query->getHandler().$name);

if (null !== $query->getCommand()) {
$request->setContentType(Request::CONTENT_TYPE_APPLICATION_JSON);
$this->buildCommand($request, $query->getCommand());
$this->buildCommand($query, $request);
} else {
// Lists one or all items.
$request->setMethod(Request::METHOD_GET);

if (null !== $term = $query->getTerm()) {
// reserved characters in a REST resource name need to be encoded twice to make it through the servlet (SOLR-6853)
$request->setHandler($request->getHandler().'/'.rawurlencode(rawurlencode($term)));
$term = rawurlencode($term);
if ($query->getUseDoubleEncoding()) {
$term = rawurlencode($term);
}

$request->setHandler($request->getHandler().'/'.$term);
}
}

return $request;
}

/**
* @param Request $request
* @param AbstractCommand $command
* @param QueryInterface|BaseQuery $query
* @param Request $request
*
* @throws RuntimeException
*
* @return self Provides fluent interface
*/
protected function buildCommand(Request $request, AbstractCommand $command): self
protected function buildCommand(QueryInterface|BaseQuery $query, Request $request): self
{
$command = $query->getCommand();

$request->setMethod($command->getRequestMethod());

switch ($command->getType()) {
case BaseQuery::COMMAND_ADD:
if (null === $rawData = $command->getRawData()) {
throw new RuntimeException('Missing data for ADD command.');
}

$request->setRawData($rawData);
break;
case BaseQuery::COMMAND_CONFIG:
if (null === $rawData = $command->getRawData()) {
throw new RuntimeException('Missing initArgs for CONFIG command.');
}

$request->setRawData($rawData);
break;
case BaseQuery::COMMAND_CREATE:
if (null === $rawData = $command->getRawData()) {
throw new RuntimeException('Missing class for CREATE command.');
}

$request->setRawData($rawData);
break;
case BaseQuery::COMMAND_DELETE:
if (null === $term = $command->getTerm()) {
throw new RuntimeException('Missing term for DELETE command.');
}
// reserved characters in a REST resource name need to be encoded twice to make it through the servlet (SOLR-6853)
$request->setHandler($request->getHandler().'/'.rawurlencode(rawurlencode($command->getTerm())));

$term = rawurlencode($term);
if ($query->getUseDoubleEncoding()) {
$term = rawurlencode($term);
}

$request->setHandler($request->getHandler().'/'.$term);
break;
case BaseQuery::COMMAND_EXISTS:
if (null !== $term = $command->getTerm()) {
// reserved characters in a REST resource name need to be encoded twice to make it through the servlet (SOLR-6853)
$request->setHandler($request->getHandler().'/'.rawurlencode(rawurlencode($command->getTerm())));
$term = rawurlencode($term);
if ($query->getUseDoubleEncoding()) {
$term = rawurlencode($term);
}

$request->setHandler($request->getHandler().'/'.$term);
}

break;
case BaseQuery::COMMAND_REMOVE:
break;
Expand Down
Loading