<commit_before><?php

/*
 * This file is part of Sulu.
 *
 * (c) MASSIVE ART WebServices GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Bundle\ArticleBundle\Controller;

use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Routing\ClassResourceInterface;
use JMS\Serializer\SerializationContext;
use ONGR\ElasticsearchBundle\Service\Manager;
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
use ONGR\ElasticsearchDSL\Query\FullText\MatchPhraseQuery;
use ONGR\ElasticsearchDSL\Query\FullText\MatchQuery;
use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\IdsQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery;
use ONGR\ElasticsearchDSL\Sort\FieldSort;
use Sulu\Bundle\ArticleBundle\Admin\ArticleAdmin;
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
use Sulu\Bundle\ArticleBundle\ListBuilder\ElasticSearchFieldDescriptor;
use Sulu\Bundle\ArticleBundle\Metadata\ArticleViewDocumentIdTrait;
use Sulu\Component\Content\Form\Exception\InvalidFormException;
use Sulu\Component\Content\Mapper\ContentMapperInterface;
use Sulu\Component\DocumentManager\DocumentManagerInterface;
use Sulu\Component\DocumentManager\Metadata\BaseMetadataFactory;
use Sulu\Component\Rest\Exception\MissingParameterException;
use Sulu\Component\Rest\Exception\RestException;
use Sulu\Component\Rest\ListBuilder\ListRepresentation;
use Sulu\Component\Rest\RequestParametersTrait;
use Sulu\Component\Rest\RestController;
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCondition;
use Sulu\Component\Security\SecuredControllerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Provides API for articles.
 */
class ArticleController extends RestController implements ClassResourceInterface, SecuredControllerInterface
{
    const DOCUMENT_TYPE = 'article';

    use RequestParametersTrait;
    use ArticleViewDocumentIdTrait;

    /**
     * Create field-descriptor array.
     *
     * @return ElasticSearchFieldDescriptor[]
     */
    private function getFieldDescriptors()
    {
        return [
            'uuid' => new ElasticSearchFieldDescriptor('id', null, 'public.id', false, false, 'string', '', '', false),
            'typeTranslation' => new ElasticSearchFieldDescriptor(
                'typeTranslation',
                'typeTranslation.raw',
                'sulu_article.list.type',
                !$this->getParameter('sulu_article.display_tab_all'),
                false
            ),
            'title' => new ElasticSearchFieldDescriptor('title', 'title.raw', 'public.title', false, true),
            'creatorFullName' => new ElasticSearchFieldDescriptor(
                'creatorFullName',
                'creatorFullName.raw',
                'sulu_article.list.creator',
                true,
                false
            ),
            'changerFullName' => new ElasticSearchFieldDescriptor(
                'changerFullName',
                'changerFullName.raw',
                'sulu_article.list.changer',
                false,
                false
            ),
            'authorFullName' => new ElasticSearchFieldDescriptor(
                'authorFullName',
                'authorFullName.raw',
                'sulu_article.author',
                false,
                false
            ),
            'created' => new ElasticSearchFieldDescriptor('created', null, 'public.created', true, false, 'datetime'),
            'changed' => new ElasticSearchFieldDescriptor('changed', null, 'public.changed', false, false, 'datetime'),
            'authored' => new ElasticSearchFieldDescriptor('authored', null, 'sulu_article.authored', false, false, 'date'),
        ];
    }

    /**
     * Returns fields.
     *
     * @return Response
     */
    public function cgetFieldsAction()
    {
        $fieldDescriptors = $this->getFieldDescriptors();

        return $this->handleView($this->view(array_values($fieldDescriptors)));
    }

    /**
     * Returns list of articles.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function cgetAction(Request $request)
    {
        $locale = $this->getRequestParameter($request, 'locale', true);

        $restHelper = $this->get('sulu_core.list_rest_helper');

        /** @var Manager $manager */
        $manager = $this->get('es.manager.default');
        $repository = $manager->getRepository($this->get('sulu_article.view_document.factory')->getClass('article'));
        $search = $repository->createSearch();

        $limit = (int) $restHelper->getLimit();
        $page = (int) $restHelper->getPage();

        if (null !== $locale) {
            $search->addQuery(new TermQuery('locale', $locale));
        }

        if (count($ids = array_filter(explode(',', $request->get('ids', ''))))) {
            $search->addQuery(new IdsQuery($this->getViewDocumentIds($ids, $locale)));
            $limit = count($ids);
        }

        if (!empty($searchPattern = $restHelper->getSearchPattern())
            && 0 < count($searchFields = $restHelper->getSearchFields())
        ) {
            $boolQuery = new BoolQuery();
            foreach ($searchFields as $searchField) {
                $boolQuery->add(new MatchPhraseQuery($searchField, $searchPattern), BoolQuery::SHOULD);
            }
            $search->addQuery($boolQuery);
        }

        if (null !== ($type = $request->get('type'))) {
            $search->addQuery(new TermQuery('type', $type));
        }

        if ($contactId = $request->get('contactId')) {
            $boolQuery = new BoolQuery();
            $boolQuery->add(new MatchQuery('changer_contact_id', $contactId), BoolQuery::SHOULD);
            $boolQuery->add(new MatchQuery('creator_contact_id', $contactId), BoolQuery::SHOULD);
            $boolQuery->add(new MatchQuery('author_id', $contactId), BoolQuery::SHOULD);
            $search->addQuery($boolQuery);
        }

        if ($categoryId = $request->get('categoryId')) {
            $search->addQuery(new TermQuery('excerpt.categories.id', $categoryId), BoolQuery::MUST);<commit_msg>improved search query for articles (#271)<commit_after><?php

/*
 * This file is part of Sulu.
 *
 * (c) MASSIVE ART WebServices GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Bundle\ArticleBundle\Controller;

use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Routing\ClassResourceInterface;
use JMS\Serializer\SerializationContext;
use ONGR\ElasticsearchBundle\Service\Manager;
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
use ONGR\ElasticsearchDSL\Query\FullText\MatchPhrasePrefixQuery;
use ONGR\ElasticsearchDSL\Query\FullText\MatchQuery;
use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\IdsQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery;
use ONGR\ElasticsearchDSL\Sort\FieldSort;
use Sulu\Bundle\ArticleBundle\Admin\ArticleAdmin;
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
use Sulu\Bundle\ArticleBundle\ListBuilder\ElasticSearchFieldDescriptor;
use Sulu\Bundle\ArticleBundle\Metadata\ArticleViewDocumentIdTrait;
use Sulu\Component\Content\Form\Exception\InvalidFormException;
use Sulu\Component\Content\Mapper\ContentMapperInterface;
use Sulu\Component\DocumentManager\DocumentManagerInterface;
use Sulu\Component\DocumentManager\Metadata\BaseMetadataFactory;
use Sulu\Component\Rest\Exception\MissingParameterException;
use Sulu\Component\Rest\Exception\RestException;
use Sulu\Component\Rest\ListBuilder\ListRepresentation;
use Sulu\Component\Rest\RequestParametersTrait;
use Sulu\Component\Rest\RestController;
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCondition;
use Sulu\Component\Security\SecuredControllerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Provides API for articles.
 */
class ArticleController extends RestController implements ClassResourceInterface, SecuredControllerInterface
{
    const DOCUMENT_TYPE = 'article';

    use RequestParametersTrait;
    use ArticleViewDocumentIdTrait;

    /**
     * Create field-descriptor array.
     *
     * @return ElasticSearchFieldDescriptor[]
     */
    private function getFieldDescriptors()
    {
        return [
            'uuid' => new ElasticSearchFieldDescriptor('id', null, 'public.id', false, false, 'string', '', '', false),
            'typeTranslation' => new ElasticSearchFieldDescriptor(
                'typeTranslation',
                'typeTranslation.raw',
                'sulu_article.list.type',
                !$this->getParameter('sulu_article.display_tab_all'),
                false
            ),
            'title' => new ElasticSearchFieldDescriptor('title', 'title.raw', 'public.title', false, true),
            'creatorFullName' => new ElasticSearchFieldDescriptor(
                'creatorFullName',
                'creatorFullName.raw',
                'sulu_article.list.creator',
                true,
                false
            ),
            'changerFullName' => new ElasticSearchFieldDescriptor(
                'changerFullName',
                'changerFullName.raw',
                'sulu_article.list.changer',
                false,
                false
            ),
            'authorFullName' => new ElasticSearchFieldDescriptor(
                'authorFullName',
                'authorFullName.raw',
                'sulu_article.author',
                false,
                false
            ),
            'created' => new ElasticSearchFieldDescriptor('created', null, 'public.created', true, false, 'datetime'),
            'changed' => new ElasticSearchFieldDescriptor('changed', null, 'public.changed', false, false, 'datetime'),
            'authored' => new ElasticSearchFieldDescriptor('authored', null, 'sulu_article.authored', false, false, 'date'),
        ];
    }

    /**
     * Returns fields.
     *
     * @return Response
     */
    public function cgetFieldsAction()
    {
        $fieldDescriptors = $this->getFieldDescriptors();

        return $this->handleView($this->view(array_values($fieldDescriptors)));
    }

    /**
     * Returns list of articles.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function cgetAction(Request $request)
    {
        $locale = $this->getRequestParameter($request, 'locale', true);

        $restHelper = $this->get('sulu_core.list_rest_helper');

        /** @var Manager $manager */
        $manager = $this->get('es.manager.default');
        $repository = $manager->getRepository($this->get('sulu_article.view_document.factory')->getClass('article'));
        $search = $repository->createSearch();

        $limit = (int) $restHelper->getLimit();
        $page = (int) $restHelper->getPage();

        if (null !== $locale) {
            $search->addQuery(new TermQuery('locale', $locale));
        }

        if (count($ids = array_filter(explode(',', $request->get('ids', ''))))) {
            $search->addQuery(new IdsQuery($this->getViewDocumentIds($ids, $locale)));
            $limit = count($ids);
        }

        if (!empty($searchPattern = $restHelper->getSearchPattern())
            && 0 < count($searchFields = $restHelper->getSearchFields())
        ) {
            $boolQuery = new BoolQuery();
            foreach ($searchFields as $searchField) {
                $boolQuery->add(new MatchPhrasePrefixQuery($searchField, $searchPattern), BoolQuery::SHOULD);
            }
            $search->addQuery($boolQuery);
        }

        if (null !== ($type = $request->get('type'))) {
            $search->addQuery(new TermQuery('type', $type));
        }

        if ($contactId = $request->get('contactId')) {
            $boolQuery = new BoolQuery();
            $boolQuery->add(new MatchQuery('changer_contact_id', $contactId), BoolQuery::SHOULD);
            $boolQuery->add(new MatchQuery('creator_contact_id', $contactId), BoolQuery::SHOULD);
            $boolQuery->add(new MatchQuery('author_id', $contactId), BoolQuery::SHOULD);
            $search->addQuery($boolQuery);
        }

        if ($categoryId = $request->get('categoryId')) {
            $search->addQuery(new TermQuery('excerpt.categories.id', $categoryId), BoolQuery::MUST);
{'fraction_non_alphanumeric': 0.12454760031471282, 'fraction_numerical': 0.0003933910306845004, 'mean_word_length': 2.974671669793621, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6937235', 'n_tokens_mistral': 3551, 'n_tokens_neox': 3441, 'n_words': 612}