Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZP-31299: Added 'search in specific language' feature #1223

Merged
merged 32 commits into from
Feb 28, 2020

Conversation

michal-myszka
Copy link
Contributor

@michal-myszka michal-myszka commented Feb 4, 2020

Question Answer
Tickets https://jira.ez.no/browse/EZP-31299
Requires ezsystems/ezpublish-kernel#2940
Bug fix? yes
New feature? yes
BC breaks? no
Tests pass? yes
Doc needed? yes
License GPL-2.0

Added 'search in specific language' feature.
This allows to search also in content translations, in one of the selected search language. The "Use always available" option is ALWAYS ENABLED here.

There are two ways of processing search, dependent on chosen search engine.

Legacy Search SQL Engine
Searching returns always "distinct" results, so one content-object couldn't be repeated in different languages (unlike in Solr engine). Results display translation is based on chosen search language or if this translation doesn't exist then the result will be present in the "locale language".

Solr Search Engine
Searching results aren't always "distinct" if the query string is provided, so one content-object could be repeated in different languages on the list (unlike LSSE) (useAlwaysAvailable and new excludeTranslationsFromAlwaysAvailable options). Results display translation is based on matched translation. If query string is omitted, then the results will be "distinct" (useAlwaysAvailable option).

  • Added dropdown in search form, if there is more than 1 language configured
  • Added new choice loader ConfiguredLanguagesChoiceLoader and ConfiguredLanguagesChoiceType for providing also non-available languages

! Required changes from ezsystems/ezpublish-kernel#2940

Checklist:

*Screens for LSSE. One more screen is in the comment with language choose popup when click on edit button from results list.

Screenshot 2020-02-14 at 10 20 09
Screenshot 2020-02-14 at 10 22 21
Screenshot 2020-02-14 at 10 22 32
Screenshot 2020-02-14 at 10 23 36
Screenshot 2020-02-14 at 10 24 25
Screenshot 2020-02-14 at 10 24 25
Screenshot 2020-02-14 at 10 24 52
Screenshot 2020-02-14 at 10 25 32
Screenshot 2020-02-14 at 10 25 45

src/bundle/Resources/views/admin/search/search.html.twig Outdated Show resolved Hide resolved
*/
public function __construct(ConfiguredLanguagesChoiceLoader $languageChoiceLoader)
{
$this->languageChoiceLoader = $languageChoiceLoader;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->languageChoiceLoader = $languageChoiceLoader;
parent::__construct($languageChoiceLoader);

{
/** @var \EzSystems\EzPlatformAdminUi\Form\Type\ChoiceList\Loader\LanguageChoiceLoader */
private $languageChoiceLoader;

/**
* @param \EzSystems\EzPlatformAdminUi\Form\Type\ChoiceList\Loader\LanguageChoiceLoader $languageChoiceLoader
*/
public function __construct(LanguageChoiceLoader $languageChoiceLoader)
{
$this->languageChoiceLoader = $languageChoiceLoader;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->languageChoiceLoader = $languageChoiceLoader;
parent::__construct($languageChoiceLoader);

use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;

abstract class LanguageChoiceTypeAbstract extends AbstractType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use Abstract prefix instead of suffix in case of abstract classes.

src/bundle/Resources/config/services/forms.yml Outdated Show resolved Hide resolved
src/bundle/Controller/SearchController.php Outdated Show resolved Hide resolved
src/bundle/Controller/SearchController.php Outdated Show resolved Hide resolved
src/bundle/Resources/config/services/forms.yml Outdated Show resolved Hide resolved
src/bundle/Resources/views/admin/search/list.html.twig Outdated Show resolved Hide resolved
/**
* Form Type allowing to select from all configured (also not enabled) Languages.
*/
class ConfiguredLanguagesChoiceType extends LanguageChoiceTypeAbstract
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of ConfiguredLanguagesChoiceType and LanguageChoiceType is almost identical, so it feels redundant. How does it happen that for ConfiguredLanguagesChoiceType the ConfiguredLanguagesChoiceLoader is injected instead? Based on the usage I don't see it (expected at least choice_loader option in \EzSystems\EzPlatformAdminUi\Form\Type\Search\SearchType::buildForm).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfiguredLanguagesChoiceType and LanguageChoiceType have injected different ChoiceLoaders, with a little different strategy. Above classes are autowiring by typehint.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above classes are autowiring by typehint.

Where exactly does the auto-wiring for that occur? The proper solution in this case is not to auto-wire, but inject directly the specific implementation (so single constructor in abstract class only and direct injection of LanguageChoiceLoader and ConfiguredLanguagesChoiceLoader). Still, can't find a place where it should happen. Form type is used as <ClassName>::class so seems like constructor is unused.

src/lib/Tab/Dashboard/PagerContentToDataMapper.php Outdated Show resolved Hide resolved
michal-myszka and others added 4 commits February 18, 2020 13:06
Co-Authored-By: Andrew Longosz <alongosz@users.noreply.github.com>
…choose after click the edit button on the search results
@dew326
Copy link
Member

dew326 commented Feb 20, 2020

Frontend part updated:
Zrzut ekranu 2020-02-20 o 12 25 05

@GrabowskiM @lucasOsti please review the last commit (7e6de36).

/cc @lserwatka

@GrabowskiM GrabowskiM self-requested a review February 20, 2020 13:56
Michał Myszka added 3 commits February 21, 2020 15:31
@michal-myszka michal-myszka self-assigned this Feb 24, 2020

/**
* @param array $data
* @param array $contentTypeIds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param array $contentTypeIds
* @param int[] $contentTypeIds

class PagerSearchContentToDataMapper extends PagerContentToDataMapperAbstract
{
/**
* @param Pagerfanta $pager
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param Pagerfanta $pager
* @param \Pagerfanta\Pagerfanta $pager

public function __construct(LanguageService $languageService, ConfigResolverInterface $configResolver)
{
$this->languageService = $languageService;
$this->siteAccessLanguages = $configResolver->getParameter('languages');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class PagerContentToDataMapper extends PagerContentToDataMapperAbstract
{
/**
* @param Pagerfanta $pager
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param Pagerfanta $pager
* @param \Pagerfanta\Pagerfanta $pager


foreach ($pager as $content) {
/** @var \eZ\Publish\API\Repository\Values\Content\Content $content */
$contentInfo = $content->getVersionInfo()->getContentInfo();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$content->getVersionInfo()->getContentInfo() could be simplified to: $content->contentInfo

Comment on lines 128 to 130
$contentType = isset($contentTypes[$item['contentTypeId']])
? $contentTypes[$item['contentTypeId']]
: $item['content']->getContentType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be simplified to $contentTypes[$item['contentTypeId']] ?? $item['content']->getContentType(). To improve readability even more you can all extract $item['contentTypeId'] to variable.

@alongosz alongosz changed the title EZP-31299 - Added 'search in specific language' feature EZP-31299: Added 'search in specific language' feature Feb 24, 2020
</div>
</div>
</div>
{% endif %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing line feed

Comment on lines +18 to +20
/**
* @param \EzSystems\EzPlatformAdminUi\Form\Type\ChoiceList\Loader\ConfiguredLanguagesChoiceLoader $languageChoiceLoader
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PHPDoc block is not really needed, the prototype provides all the necessary information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is more accurate information (prototype type-hint is only ChoiceLoaderInterface, because inheriting classes have different implementations)

Comment on lines 40 to 46
/**
* @param \eZ\Publish\API\Repository\ContentTypeService $contentTypeService
* @param \eZ\Publish\API\Repository\UserService $userService
* @param \eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider
* @param \eZ\Publish\Core\Helper\TranslationHelper $translationHelper
* @param \eZ\Publish\API\Repository\LanguageService $languageService
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be skipped as doesn't provide anything more than the prototype (note: we've recently decided to skip that, so we'll find such cases in the codebase).

Copy link
Contributor

@ViniTou ViniTou Feb 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand it goes to 1.5 so ¯\(ツ)

/**
* Form Type allowing to select from all configured (also not enabled) Languages.
*/
class ConfiguredLanguagesChoiceType extends LanguageChoiceTypeAbstract
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above classes are autowiring by typehint.

Where exactly does the auto-wiring for that occur? The proper solution in this case is not to auto-wire, but inject directly the specific implementation (so single constructor in abstract class only and direct injection of LanguageChoiceLoader and ConfiguredLanguagesChoiceLoader). Still, can't find a place where it should happen. Form type is used as <ClassName>::class so seems like constructor is unused.

use EzSystems\EzPlatformAdminUi\Specification\ContentIsUser;
use EzSystems\EzPlatformAdminUi\Specification\UserExists;

class PagerContentToDataMapperAbstract
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this class abstract or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is. Corrected

* @param array $data
* @param array $contentTypeIds
*/
protected function setTranslatedContentTypesNames(array &$data, array $contentTypeIds): void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not rly fan of passing array by reference, but if no one protests ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand :) also not a rly fan of this method, but it's only moved from another place with little refactor (not more time in this task)

@michal-myszka
Copy link
Contributor Author

Above classes are autowiring by typehint.

Where exactly does the auto-wiring for that occur? The proper solution in this case is not to auto-wire, but inject directly the specific implementation (so single constructor in abstract class only and direct injection of LanguageChoiceLoader and ConfiguredLanguagesChoiceLoader). Still, can't find a place where it should happen. Form type is used as ::class so seems like constructor is unused.

@alongosz the logic for getting service starts here: \Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension::getType()

The constructors are used and I've verified, that they receive the correct dependency implementations.

@alongosz
Copy link
Member

the logic for getting service starts here: \Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension::getType()

The constructors are used and I've verified, that they receive the correct dependency implementations.

Given the amount of lines of code which was required for that auto-wiring to work and the static analysis issues which this led to, I would say that the best approach is to keep one LanguageType and configure proper Choice Loaders when building forms.

POV ping @webhdx

/**
* @param \EzSystems\EzPlatformAdminUi\Form\Type\ChoiceList\Loader\LanguageChoiceLoader $languageChoiceLoader
*/
public function __construct(LanguageChoiceLoader $languageChoiceLoader)
{
$this->languageChoiceLoader = $languageChoiceLoader;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you are doing here is wrong. You don't need AbstractLanguageChoiceType. Since you only need to change choice loader in your types, then use choice_loader option. Do not create X additional classes to achieve what is already handled well by Symfony.

$formBuilder->add('configured_language_choice_type', LanguageChoiceType::class, [
    'choice_loader' => new ConfiguredLanguagesChoiceLoader(), // or inject from DIC
];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check, that I'm using the choice_loader option (see in AbstractLanguageChoiceType). I considered two options - your approach and current implementation, bu I've finally decided, that current solution may be better. I want to create X additional classes, as you suggest, but I think these two field types are useful and convenient to use - when you build your form, you have only to use the requested field type, with appropriate choices.

'search_language',
ConfiguredLanguagesChoiceType::class,
[
'required' => false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my above comment. Here you could just use choice_loader option on LanguageChoiceType to avoid adding very specific ConfiguredLanguagesChoiceType class.

@@ -55,7 +56,7 @@ class SearchController extends Controller

/**
* @param \eZ\Publish\API\Repository\SearchService $searchService
* @param \EzSystems\EzPlatformAdminUi\Tab\Dashboard\PagerContentToDataMapper $pagerContentToDataMapper
* @param \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper $pagerSearchContentToDataMapper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong type, should be \EzSystems\EzPlatformAdminUi\Search\PagerSearchContentToDataMapper

/**
* @deprecated This class has been moved to \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper
*/
class PagerContentToDataMapper extends \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper is not used anywhere but on a dashboard tab. If so, please remove \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper and extend AbstractPagerContentToDataMapper here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This \EzSystems\EzPlatformAdminUi\Search\PagerContentToDataMapper is using in dashboard tabs, but the results becomes from Search engines (at least for now). I'm not sure about move AbstractPagerContentToDataMapper to dashboard "domain" because this class are extending also by \EzSystems\EzPlatformAdminUi\Search\PagerSearchContentToDataMapper, which is not a part of dashboard "domain", but all three classes are connected by search feature now. Maybe we should move them all to namespace like "Mapper" or "PagerContent" for more independent .. what do you think @webhdx ?

…oader.php

Co-Authored-By: Adam Wójs <adam.wojs@ez.no>
@lserwatka lserwatka merged commit b6cf000 into 1.5 Feb 28, 2020
@lserwatka lserwatka deleted the ezp-31299-additional-search-languages-filter branch February 28, 2020 13:25
@lserwatka
Copy link
Member

Could you merge it up?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

10 participants