Skip to content

[Improvement]: [Seo] Allow redirect targets to be data objects or assets - #2155

Open
dolmit-tanel-paaro wants to merge 9 commits into
pimcore:2026.xfrom
dolmit-tanel-paaro:feature/seo-redirect-target-types
Open

dolmit-tanel-paaro wants to merge 9 commits into
pimcore:2026.xfrom
dolmit-tanel-paaro:feature/seo-redirect-target-types

Conversation

@dolmit-tanel-paaro

@dolmit-tanel-paaro dolmit-tanel-paaro commented Oct 26, 2026 •

Copy link
Copy Markdown

Changes in this pull request

Resolves pimcore/platform-version#707

Tracked in pimcore/pimcore#15398

Companion to pimcore/pimcore#18293, which lets a redirect target be a data object or an asset instead of always a document. Part of pimcore/pimcore#15398.

Without this, the Studio API resolves every redirect target as a document, so the new target types are only reachable via SQL or CSV import.

  • BundleSeoRedirect, BundleSeoRedirectAdd and BundleSeoRedirectUpdate carry a targetType (document / asset / object).
  • RedirectHydrator resolves a numeric target back to its path using that type, falling back to document so redirects created before target types existed keep working.
  • RedirectsService resolves the submitted path to an element ID:
    • a submitted targetType restricts the lookup, which is how a path existing in more than one tree is disambiguated;
    • without one the element types are tried in order - documents first, preserving the previous behaviour;
    • a target that resolves to no element stays a plain URL and the type is cleared;
    • an unknown type is rejected with InvalidArgumentException.
  • RedirectHydratorTest covers document, asset, legacy untyped and non-element targets.

Additional info

Requires the core PR: targetType and the Pimcore\Model\Element\ElementType enum come from pimcore/pimcore#18293. targetType is optional in the add/update schemas, so clients that do not send it behave exactly as before.

The UI counterpart is pimcore/studio-ui-bundle#4269.

Verified against a 2026.x instance with Studio: adding/updating with each target type, type detection, an explicit type restricting the lookup, legacy untyped rows, and the generated OpenAPI schema.

dolmit-tanel-paaro and others added 3 commits October 25, 2026 19:36
Accepts and returns the targetType introduced in pimcore/pimcore#18293, so a
redirect target can be a document, an asset or a data object instead of always
being resolved as a document.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Typing an asset or data object path previously resolved only against documents,
so it was stored as a plain URL. The submitted type now restricts the lookup for
disambiguation, and is detected when absent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The public response constructor breaks compatibility, and unsupported object targets can be saved as nonfunctional redirects.

2 open issues
What changed in this PR

Verdict: Needs changes. This PR extends Studio’s SEO redirect API to support asset and data-object targets alongside documents, using the companion core changes in pimcore/pimcore#18293.

Changes:

  • Adds targetType to redirect response and request schemas.
  • Resolves submitted paths by explicit type or automatic detection, while retaining legacy document fallback during hydration.
  • Adds focused hydrator tests for documents, assets, legacy targets and plain URLs.

The service and hydrator changes address the document-only assumption at the appropriate boundary (RedirectsService.php:65,94,237–255; RedirectHydrator.php:60–70). Both add and update use the shared resolution logic. Tests cover hydration, but service eligibility behavior and full integration were not verified by execution; request documentation also needs alignment with automatic detection.

File Description
tests/​Unit/​Bundle/​Seo/​Hydrator/​RedirectHydratorTest.php Tests typed, legacy and plain-URL hydration.
src/​Bundle/​Seo/​Service/​RedirectsService.php Resolves paths and persists target types.
src/​Bundle/​Seo/​Schema/​RedirectUpdateParameters.php Accepts an optional target type on updates.
src/​Bundle/​Seo/​Schema/​RedirectAddParameters.php Accepts an optional target type on creation.
src/​Bundle/​Seo/​Schema/​Redirect.php Exposes target type in responses.
src/​Bundle/​Seo/​Hydrator/​RedirectHydrator.php Resolves numeric targets using their element type.

Review effort: Balanced

Comment thread src/Bundle/Seo/Schema/Redirect.php Outdated
example: 'document',
nullable: true
)]
public readonly ?string $targetType,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 60781d7. targetType is now the last constructor argument with a null default, so positional arguments keep their positions and a named call that omits it still works. It stays in the schema's required list, since the response always carries it (null for a redirect to a plain URL).

Comment on lines +245 to +247
if ($element !== null) {
$redirect->setTarget((string)$element->getId());
$redirect->setTargetType($candidate);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, and this is already addressed - the change landed in pimcore/pimcore@683c49e759 and 86ffed8 before this review ran, so the diff you looked at predates it.

TargetResolverInterface::isUsableAsTarget() decides whether an element can be a redirect target at all - not a folder, not a snippet or an email, and not a data object whose class has no link generator - and resolveElement() returns null for anything it rejects. That gives exactly the three behaviours you describe:

  • eligibility is checked before the path is converted;
  • detectElement() passes over an ineligible candidate, so an auto-detected target that matches one stays a literal URL with no type;
  • an explicitly submitted target type that resolves to nothing usable is rejected with No <type> usable as a redirect target found at "<path>" (422), which is also what the CSV import does for the same row.

RedirectHandler::resolveElementTarget() asks the same method rather than restating the rule, and still re-checks at request time - a class can lose its link generator after the redirect was saved.

dolmit-tanel-paaro and others added 4 commits October 26, 2026 11:11
Keeps the path<->element-ID rules in one place, so the Studio API and the CSV
import cannot drift apart on what a redirect target means.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Detection is now an explicit call: a client that sends a target type restricts
the lookup to that tree, one that sends none has the type detected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- an update that touches neither the target nor its type no longer re-resolves
  it, so a round trip of a redirect whose element is gone keeps the type
- a submitted target type that names no such element is rejected, as the CSV
  import already does, instead of silently storing a plain URL
- targetType is nullable, so null belongs in its OpenAPI enum
- the target type is validated before the loaded model is mutated

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A required argument in the middle of the constructor shifts every positional
argument after it and breaks named calls that do not pass it. The field stays
required in the response schema.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dolmit-tanel-paaro
dolmit-tanel-paaro marked this pull request as ready for review October 27, 2026 06:52
@pimcore-deployments
pimcore-deployments marked this pull request as draft October 27, 2026 06:52
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

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.

[Feature]: Allow redirect targets to be data objects or assets

3 participants