eZ Platform Discussions

Sort by DatePublished and field publish_date

version22

#1

Bonjour.

How to sort contents according to a “publish_date” field if it is entered and the publication date (that of the eZ system).

Content A : real publish date 10. No data in field “publish_date”
Content B : real publish date 20. Data in field “publish_date” : 05
Content C : real publish date 30. No data in field “publish_date”

I went B(05), A(10), C(30)

        $query = new LocationQuery();

        $query->filter = new Criterion\LogicalAnd([
            new Criterion\ContentTypeIdentifier(['article', 'breve']),
        ]);
        $query->sortClauses = [
            new SortClause\DatePublished(Query::SORT_DESC),
            // new SortClause\Field('article', 'publish_date', Query::SORT_DESC), // Ne fonctionne pas pour 2 raisons. 1 il faut préciser le type. 2 on ne veux pas trier par date de publication réél puis par date de publication.
        ];

Does not work for 2 reasons. 1 the type must be specified. 2 you do not want to sort by actual publication date then by publication date.

Note: I use SOLR :slight_smile:

Merci pour votre aide.


#2

Salut !

I have created a Document Field Mappers
https://doc.ezplatform.com/en/2.2/guide/solr/#extending-the-solr-search-engine-bundle

namespace MyBundle\DocumentFieldMappers;

use eZ\Publish\API\Repository\Repository;
use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\ContentFieldMapper;
use eZ\Publish\SPI\Persistence\Content;
use eZ\Publish\SPI\Search;

class PublishDateFieldMapper extends ContentFieldMapper
{
    protected $repository;

    public function __construct(Repository $repository) {
        $this->repository = $repository;
    }

    public function accept(Content $content)
    {
        return in_array($content->versionInfo->contentInfo->contentTypeId, [2/*Article*/, 51/*breve*/]);
    }

    public function mapFields(Content $content)
    {
        $v = $content->versionInfo->contentInfo->publicationDate; // int

        $c = $this->repository->getContentService()->loadContent($content->versionInfo->contentInfo->id);
        // Isn't it too overkill to load content here? 

        /** @var \eZ\Publish\Core\FieldType\DateAndTime\Value $f */
        $f = $c->getFieldValue('publish_date');
        if ($f && $f->value && $f->value->getTimestamp()) {
            $v = $f->value->getTimestamp();
        }

        return [
            new Search\Field(
                'publish_date',
                $v,
                new Search\FieldType\DateField()
            ),
        ];
    }
}

service.yml:

    my.document_field_mappers.publish_date:
        class: MyBundle\DocumentFieldMappers\PublishDateFieldMapper
        arguments:
            - '@ezpublish.api.repository'
        tags:
            #- {name: ezpublish.search.solr.field_mapper.content} # Only content
            - {name: ezpublish.search.solr.field_mapper.block} # Content and Location :)

Now I just have to understand how to use it in my query.

        $query = new LocationQuery();
        $query->sortClauses = [ // TODO
            //new SortClause\DatePublished(Query::SORT_DESC),
            //new SortClause\Field('article', 'publish_date', Query::SORT_DESC), // Ne fonctionne pas pour 2 raisons. 1 il faut préciser le type. 2 on ne veux pas trier par date de publication réél puis par date de publication.
        ];

#3

I changed field_mapper. I put block in place of content

ezpublish.search.solr.field_mapper.block

In my Solr I have well the new indexed field.

http://localhost:35983/solr/collection1/select?indent=on&q=content_id_id:122&wt=json

    "publish_date_dt":"2018-05-25T10:00:00Z",

But how do you use it in the sortClauses ?

new SortClause\Solr("publish_date_dt", Query::SORT_DESC) // DOES NOT EXISTE !

#4

Hello.

If I follow your explanations correctly, you want to sort on either the publication date field, if it is set, or on the content item’s publication date.

I kind of like your idea of customizing the publication date, since there is a criterion for that. It uses the field content_publication_date_dt, not publish_date_dt. Could you change your mapper so that it writes to that solr field ?

Then you should be able to use the DatePublished sort clause.


#5

Hy @bertrand.dunogier,

It would probably work. But it would deprive me of the ability to filter on the real publication date…

In addition. I have other similar problems that cannot be solved in this way.
For example: I have several types of content with a numeric field. And I want to be able to sort these contents according to the value of this field.


#6

But it would deprive me of the ability to filter on the real publication date…

Do you need to ? It seems to me that for those items, the real publication date is the one chosen by your mapper. But if you want it as a custom field, then I need to know more about the error you report when using new SortClause\Solr("publish_date_dt", Query::SORT_DESC). What do you mean by “does not exist” ?


#7

I mean the class SortClause\Solr doesn’t exist.
This imaginary SortClause allows you to sort on a Solr field.
I have no idea how to make it real.


#8

I mean the class SortClause\Solr doesn’t exist.

I didn’t pay attention to that part :slight_smile:

I’d say that you need to create a custom SortClause and a custom Solr SortClauseVisitor.

The SortClause is a simple value object, almost identical to eZ\Publish\API\Repository\Values\Content\Query\SortClause\DatePublished.

As for the SortClauseVisitor, you can start from EzSystems\EzPlatformSolrSearchEngine\Query\Common\SortClauseVisitor\DatePublished. It needs to be defined as a service, and tagged accordingly:

    AppBundle\Solr\SortClauseVisitor\DatePublished:
        tags:
            - {name: ezpublish.search.solr.query.content.sort_clause_visitor}
            - {name: ezpublish.search.solr.query.location.sort_clause_visitor}

The visitor should of course use the custom field you add to the index.
I hope it helps.


#9

Merci @bertrand.dunogier.

I think I’m almost there…

CustomDatePublishedSortClause.php

namespace MyBundle\SortClauseHandler;
use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
class CustomDatePublishedSortClause extends SortClause
{
    public function __construct($sortDirection = Query::SORT_ASC)
    {
        parent::__construct('date_published', $sortDirection);
    }
}

CustomDatePublishedSortClauseVisitor.php

namespace Edb\PressePro3Bundle\SortClauseHandler;
use EzSystems\EzPlatformSolrSearchEngine\Query\SortClauseVisitor;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
class CustomDatePublishedSortClauseVisitor extends SortClauseVisitor
{
    public function canVisit(SortClause $sortClause)
    {
        return $sortClause instanceof CustomDatePublishedSortClause;
    }

    public function visit(SortClause $sortClause)
    {
        return 'publication_date_dt' . $this->getDirection($sortClause);
    }
}

service.yml

    my.search.solr.query.location.sort_clause_visitor.custom_publish_date:
        class: MyBundle\SortClauseHandler\CustomDatePublishedSortClauseVisitor
        tags:
            - {name: ezpublish.search.solr.query.content.sort_clause_visitor}
            - {name: ezpublish.search.solr.query.location.sort_clause_visitor}

In my controller :

        $query->sortClauses = [
            new CustomDatePublishedSortClause(Query::SORT_DESC),
        ];

But this has no impact on the sorting.

However, it was sent to SOLR.

/home/relim/docker/edb/ezplatform/vendor/ezsystems/ezplatform-solr-search-engine/lib/Gateway/Native.php

    protected function search(array $parameters)
    {
        $queryString = $this->generateQueryString($parameters);

/* LINE 448 */ dump($parameters, $queryString); die();
        // ...
    }

Debug =>

Native.php on line 448: array:8 [
  "defType" => "edismax" 
  "q" => "{!lucene}*:*" 
  "fq" => "{!lucene}((document_type_id:"location") AND (meta_indexed_is_main_translation_b:"true") AND ((content_type_id_id:"2" OR content_type_id_id:"51" OR content_type_id_id:"52") AND (path_string_id:\/1\/2\/60\/126\/*) AND (content_section_id_id:"1" OR content_section_id_id:"3")))"
  "sort" => "publication_date_dt desc" 
  "start" => 0 
  "rows" => 0 
  "fl" => "*,score,[shard]" 
  "wt" => "json" 
]
Native.php on line 448:
"defType=edismax&q=%7B%21lucene%7D%2A%3A%2A&fq=%7B%21lucene%7D%28%28document_type_id%3A%22location%22%29+AND+%28meta_indexed_is_main_translation_b%3A%22true%22%29+AND+%28%28content_type_id_id%3A%222%22+OR+content_type_id_id%3A%2251%22+OR+content_type_id_id%3A%2252%22%29+AND+%28path_string_id%3A%5C%2F1%5C%2F2%5C%2F60%5C%2F126%5C%2F%2A%29+AND+%28content_section_id_id%3A%221%22+OR+content_section_id_id%3A%223%22%29%29%29&sort=publication_date_dt+desc&start=0&rows=0&fl=%2A%2Cscore%2C%5Bshard%5D&wt=json"

http://localhost:35983/solr/collection1/select?fl=publish_date_dt,%20content_name_s&fq=((document_type_id:%22location%22)%20AND%20(meta_indexed_is_main_translation_b:%22true%22)%20AND%20((content_type_id_id:%222%22%20OR%20content_type_id_id:%2251%22%20OR%20content_type_id_id:%2252%22)%20AND%20(path_string_id:\/1\/2\/60\/126\/*)%20AND%20(content_section_id_id:%221%22%20OR%20content_section_id_id:%223%22)))&indent=on&q=*:*&rows=20&sort=publish_date_dt%20desc&wt=json

And if I search directly in Solr, the results are well sorted.


#10

Fixed a typo and it works :slight_smile:

CustomDatePublishedSortClause.php

        parent::__construct('publish_date', $sortDirection);

CustomDatePublishedSortClauseVisitor.php

        return 'publish_date_dt' . $this->getDirection($sortClause);

In accordance with my Field Mapper :
PublishDateFieldMapper

       return [
            new Search\Field(
                'publish_date',
                $v,
                new Search\FieldType\DateField()
            ),
        ];

Merci @bertrand.dunogier.


#11

Great.
I’m happy that it worked, Remy :slight_smile:


#12

Me to :wink:

I think this doc is not uptodate : https://doc.ezplatform.com/en/1.7/guide/search/#how-to-configure-your-own-criterion-and-sort-clause-handlers