Skip to content

NGSTACK-906 eztags priority sorting #170

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

Open
wants to merge 45 commits into
base: master
Choose a base branch
from

Conversation

AntePrkacin
Copy link

Two main things:

  • added priority property to the Tag object
  • added functionality to sort tags by either id, keyword, modified or priority

The sorting functionality is added below the children list for some tag. If tag has no children, then the sorting functionality is not rendered at all.

The sorting works by modifying the getChildren() method in the Gateway layer. It first sorts and orders the fetched data and then slices it by using offset and limit values.

@AntePrkacin AntePrkacin self-assigned this Jun 20, 2025
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to read tags
*
* @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList
*/
public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList;
public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?string $sortBy = null, ?string $sortOrder = null): TagList;
Copy link
Member

Choose a reason for hiding this comment

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

Do we need this level of control, in contrast to just using whatever info is storred on parent tag?

Copy link
Author

@AntePrkacin AntePrkacin Jun 24, 2025

Choose a reason for hiding this comment

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

I think this level of control is necessary because in the Gateway layer (getChildren() method), the fetched data from the database needs to first be sorted and then sliced using $limit and $offset values.

Which info stored on parent tag do you mean? Perhaps another approach for sorting would be if each Tag object would have information attached to it about the sortBy and sortOrder, something like the Location object in Ibexa has (if I'm not mistaken).

EDIT: read the comment below this one. OK, I will implement the sorting mechanism similar to the Ibexa one

@@ -45,6 +45,12 @@ public function showTagAction(Request $request, ?Tag $tag = null): Response
if (!$tag instanceof Tag || !$tag->isSynonym()) {
$configResolver = $this->getConfigResolver();

$sortBy = $request->query->get('sort_by');
Copy link
Member

Choose a reason for hiding this comment

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

I was under the impression that the sorting mechanism will be stored on parent tag, similar to how Ibexa does it in their locations. That way, you don't need to set the sorting for every children fetch, it will automatically fetch tags with the defined sort.

Default sort can then be set in configuration.

->setMaxResults($limit > 0 ? $limit : PHP_INT_MAX);
)->setParameter('parent_id', $tagId, Types::INTEGER);

if ($sortBy !== null && $sortOrder !== null) {
Copy link
Member

Choose a reason for hiding this comment

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

We should have an enum with allowed sorting property and sorting directions, so we don't need to pass direct values. This way, we would only allow sorting by predefined columns, and not besically anything the user sends down the method call chain.

Copy link
Author

Choose a reason for hiding this comment

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

Added enums for sortBy and sortOrder: 4224d33
Also used enum cases to iterate over different options when selecting the property by which the user wants to sort the tags.

$tagIdsQuery->orderBy('eztags.keyword', 'ASC');
}

$tagIdsQuery
Copy link
Member

Choose a reason for hiding this comment

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

You don't need to separate setFirstResult and setMaxResults method calls from the main query builder calls.

Copy link
Author

Choose a reason for hiding this comment

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

I put it back together, after refactoring the whole process of sorting children tags

$sortOrder = $request->request->get('sort_order');

$tagUpdateStruct = new TagUpdateStruct();
$tagUpdateStruct->sortField = TagSortField::from((string) $sortBy);
Copy link
Member

Choose a reason for hiding this comment

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

You can use ::tryFrom here, catch the exception and throw BadRequestHttpException. Otherwise, transfering an invalid value would get you error 500.

Copy link
Author

Choose a reason for hiding this comment

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

Did so here: e16f73f

@@ -128,6 +128,10 @@ public function getFullTagDataByKeywordAndParentId(string $keyword, int $parentI

public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array
{
$tagData = $tagId !== 0 ? $this->getBasicTagData($tagId) : [];
$sortBy = $tagData['sort_by'] ?? 'id';
Copy link
Member

Choose a reason for hiding this comment

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

We should add configuration for the default sort.

We also need configuration for the default sort for root tag (which has ID = 0), since we can't store this in the database.

Copy link
Member

Choose a reason for hiding this comment

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

You can also try to instantiate the enum to double check that the value stored in the database is an allowed stored type and direction.

Copy link
Author

@AntePrkacin AntePrkacin Jun 25, 2025

Choose a reason for hiding this comment

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

First four commits made on 25 June 2025 are regarding the config parameters for default sorting.

There are two new config parameters added:

  • one for default sorting of all child tags (sort.by and sort.order)
  • one for default sorting of root tag children (sort.root.by and sort.root.order)

These config parameters are enums (enumNode), so their values will always match the cases of enum. There is even an option to put an enum class in the node, but that is only for Symfony 7.3 (I don't know which Symfony versions you want this bundle to support).

Also, in the database, the 'sort_by' and 'sort_order' column types were changed from enums to just varchar(100). By default, when a new tag is added, it will have empty string ('') NULL set at 'sort_by' and 'sort_order' columns - in this case, these two new config parameters will be fetched for sorting.
Only when the user sorts the children tags of some tag, then will the 'sort_by' and 'sort_order' columns be set for that (parent) tag.

This was done because the <someEnum>::tryFrom() method returns null if the corresponding (given) string has no matching case. In that case, the configResolver is used to get a parameter. Example:

$tag->sortBy = TagSortBy::tryFrom($row['sort_by'])
                        ?? TagSortBy::from($this->configResolver->getParameter('sort.by', 'netgen_tags'));

@AntePrkacin
Copy link
Author

AntePrkacin commented Jun 25, 2025

Should the dropdowns for sorting by and sorting order be added/shown to the 'Top level tags'? Or is it good enough to just be able to set the sort.root.by and sort.root.order config parameters for sorting the children of the 'Top level tags'?

@AntePrkacin
Copy link
Author

148a3c3
Added ability to change the priority property when editing a certain tag. Also, the information about tag priority will be displayed below the tag title (along with Tag ID, Remote ID and Modified properties).

@emodric
Copy link
Member

emodric commented Jun 25, 2025

We don't have anywhere to store this info, so for now, the config is good enough for top level tags.

…base to properly handle the case when sortBy or sortOrder is null
…sortOrder is null and extracted that logic in a separate function
…sortOrder is null and fix TagsIntegrationTest
@AntePrkacin
Copy link
Author

59beb45 84d9758 fd507dd a81d3f6
There was a problem when editing a certain tag. For example, when you went to edit a priority for some tag and hit 'save', the sort_by and sort_order properties (and columns in the database) would automatically be assigned the default values (from the config params).

I wanted to avoid this because then, if someone changes the config params for default sorting, the sorting will not change for this one tag because (unintentionally) editing the tag already set the sorting.

With the commits I pasted above, this problem is handled by making the sortBy and sortOrder properties be null (by default - both for the database and for the entity). ONLY when the user clicks to sort the tags (the thing the user can click below the children list in adminUI), only then are the sort_by and sort_order columns set in the database.

…'sort_by' and 'sort_order' columns and updated the UPGRADE doc
@AntePrkacin
Copy link
Author

AntePrkacin commented Jun 26, 2025

0ce8c25
Updated the doc/UPGRADE.md file with update instructions for this PR. Also added the upgrade scripts to add priority, sort_by and sort_order columns to eztags table.

3e9628a
Removed 'priority' info when showing synonyms and removed the 'priority' field when editing or adding a synonym to some tag. I think it makes no sense to show 'priority' info on synonyms, since there is no sorting for them at all. These synonyms will still have priority be 0 in the database, but that data won't be shown anywhere.

031c1aa
Added policy for sorting

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

Successfully merging this pull request may close these issues.

2 participants