Skip to content
This repository was archived by the owner on Dec 19, 2019. It is now read-only.

Added URL rewrites data to the product interface #107

Merged
merged 17 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/code/Magento/CatalogUrlRewriteGraphQl/etc/module.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magento_CatalogUrlRewriteGraphQl" />
<module name="Magento_CatalogUrlRewriteGraphQl" >
<sequence>
<module name="Magento_UrlRewriteGraphQl"/>
<module name="Magento_CatalogGraphQl"/>
</sequence>
</module>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
interface ProductInterface {
url_key: String @doc(description: "The part of the URL that identifies the product")
url_path: String @doc(description: "The part of the URL that precedes the url_key")
url_rewrites: [UrlRewrite] @doc(description: "URL rewrites list") @resolver(class: "Magento\\UrlRewriteGraphQl\\Model\\Resolver\\UrlRewrite")
}

input ProductFilterInput {
Expand Down
148 changes: 148 additions & 0 deletions app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\UrlRewriteGraphQl\Model\Resolver;

use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use Magento\UrlRewriteGraphQl\Model\Resolver\UrlRewrite\CustomUrlLocatorInterface;

/**
* UrlRewrite field resolver, used for GraphQL request processing.

Choose a reason for hiding this comment

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

As EntityUrl and UrlRewrite are pretty similar it is better to describe their purpose in class comments (now both classes have same description so to understand what is needed source code should be explored)

*/
class EntityUrl implements ResolverInterface
{
/**
* @var UrlFinderInterface
*/
private $urlFinder;

/**
* @var StoreManagerInterface
*/
private $storeManager;

/**
* @var CustomUrlLocatorInterface
*/
private $customUrlLocator;

/**
* @param UrlFinderInterface $urlFinder
* @param StoreManagerInterface $storeManager
* @param CustomUrlLocatorInterface $customUrlLocator
*/
public function __construct(
UrlFinderInterface $urlFinder,
StoreManagerInterface $storeManager,
CustomUrlLocatorInterface $customUrlLocator
) {
$this->urlFinder = $urlFinder;
$this->storeManager = $storeManager;
$this->customUrlLocator = $customUrlLocator;
}

/**
* @inheritdoc
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
if (!isset($args['url']) || empty(trim($args['url']))) {
throw new GraphQlInputException(__('"url" argument should be specified and not empty'));
}

$result = null;
$url = $args['url'];
if (substr($url, 0, 1) === '/' && $url !== '/') {
$url = ltrim($url, '/');
}
$customUrl = $this->customUrlLocator->locateUrl($url);
$url = $customUrl ?: $url;
$urlRewrite = $this->findCanonicalUrl($url);
if ($urlRewrite) {
$result = [
'id' => $urlRewrite->getEntityId(),
'canonical_url' => $urlRewrite->getTargetPath(),
'type' => $this->sanitizeType($urlRewrite->getEntityType())
];
}
return $result;
}

/**
* Find the canonical url passing through all redirects if any
*
* @param string $requestPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
*/
private function findCanonicalUrl(string $requestPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
{
$urlRewrite = $this->findUrlFromRequestPath($requestPath);
if ($urlRewrite && $urlRewrite->getRedirectType() > 0) {
while ($urlRewrite && $urlRewrite->getRedirectType() > 0) {
$urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath());
}
}
if (!$urlRewrite) {
$urlRewrite = $this->findUrlFromTargetPath($requestPath);
}

return $urlRewrite;
}

/**
* Find a url from a request url on the current store
*
* @param string $requestPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
*/
private function findUrlFromRequestPath(string $requestPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
{
return $this->urlFinder->findOneByData(
[
'request_path' => $requestPath,
'store_id' => $this->storeManager->getStore()->getId()
]
);
}

/**
* Find a url from a target url on the current store
*
* @param string $targetPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
*/
private function findUrlFromTargetPath(string $targetPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
{
return $this->urlFinder->findOneByData(
[
'target_path' => $targetPath,
'store_id' => $this->storeManager->getStore()->getId()
]
);
}

/**
* Sanitize the type to fit schema specifications
*
* @param string $type
* @return string
*/
private function sanitizeType(string $type) : string
{
return strtoupper(str_replace('-', '_', $type));
}
}
127 changes: 36 additions & 91 deletions app/code/Magento/UrlRewriteGraphQl/Model/Resolver/UrlRewrite.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Model\AbstractModel;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use Magento\UrlRewriteGraphQl\Model\Resolver\UrlRewrite\CustomUrlLocatorInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteDTO;

/**
* UrlRewrite field resolver, used for GraphQL request processing.
* Returns URL rewrites list for the specified product
*/
class UrlRewrite implements ResolverInterface
{
Expand All @@ -25,29 +25,13 @@ class UrlRewrite implements ResolverInterface
*/
private $urlFinder;

/**
* @var StoreManagerInterface
*/
private $storeManager;

/**
* @var CustomUrlLocatorInterface
*/
private $customUrlLocator;

/**
* @param UrlFinderInterface $urlFinder
* @param StoreManagerInterface $storeManager
* @param CustomUrlLocatorInterface $customUrlLocator
*/
public function __construct(
UrlFinderInterface $urlFinder,
StoreManagerInterface $storeManager,
CustomUrlLocatorInterface $customUrlLocator
UrlFinderInterface $urlFinder
) {
$this->urlFinder = $urlFinder;
$this->storeManager = $storeManager;
$this->customUrlLocator = $customUrlLocator;
}

/**
Expand All @@ -59,90 +43,51 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
) {
if (!isset($args['url']) || empty(trim($args['url']))) {
throw new GraphQlInputException(__('"url" argument should be specified and not empty'));
): array {
if (!isset($value['model'])) {
throw new GraphQlInputException(__('"model" value should be specified'));
}

$result = null;
$url = $args['url'];
if (substr($url, 0, 1) === '/' && $url !== '/') {
$url = ltrim($url, '/');
}
$customUrl = $this->customUrlLocator->locateUrl($url);
$url = $customUrl ?: $url;
$urlRewrite = $this->findCanonicalUrl($url);
if ($urlRewrite) {
$result = [
'id' => $urlRewrite->getEntityId(),
'relative_url' => $urlRewrite->getTargetPath(),
'type' => $this->sanitizeType($urlRewrite->getEntityType())
];
}
return $result;
}
/** @var AbstractModel $entity */
$entity = $value['model'];
$entityId = $entity->getEntityId();

/**
* Find the canonical url passing through all redirects if any
*
* @param string $requestPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
*/
private function findCanonicalUrl(string $requestPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
{
$urlRewrite = $this->findUrlFromRequestPath($requestPath);
if ($urlRewrite && $urlRewrite->getRedirectType() > 0) {
while ($urlRewrite && $urlRewrite->getRedirectType() > 0) {
$urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath());
$urlRewriteCollection = $this->urlFinder->findAllByData([UrlRewriteDTO::ENTITY_ID => $entityId]);
$urlRewrites = [];

/** @var UrlRewriteDTO $urlRewrite */
foreach ($urlRewriteCollection as $urlRewrite) {
if ($urlRewrite->getRedirectType() !== 0) {
continue;
}

$urlRewrites[] = [
'url' => $urlRewrite->getRequestPath(),
'parameters' => $this->getUrlParameters($urlRewrite->getTargetPath())
];
}
if (!$urlRewrite) {
$urlRewrite = $this->findUrlFromTargetPath($requestPath);
}

return $urlRewrite;
}

/**
* Find a url from a request url on the current store
*
* @param string $requestPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
*/
private function findUrlFromRequestPath(string $requestPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
{
return $this->urlFinder->findOneByData(
[
'request_path' => $requestPath,
'store_id' => $this->storeManager->getStore()->getId()
]
);
return $urlRewrites;
}

/**
* Find a url from a target url on the current store
* Parses target path and extracts parameters
*
* @param string $targetPath
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|null
* @return array
*/
private function findUrlFromTargetPath(string $targetPath) : ?\Magento\UrlRewrite\Service\V1\Data\UrlRewrite
private function getUrlParameters(string $targetPath): array
{
return $this->urlFinder->findOneByData(
[
'target_path' => $targetPath,
'store_id' => $this->storeManager->getStore()->getId()
]
);
}
$urlParameters = [];
$targetPathParts = explode('/', trim($targetPath, '/'));

/**
* Sanitize the type to fit schema specifications
*
* @param string $type
* @return string
*/
private function sanitizeType(string $type) : string
{
return strtoupper(str_replace('-', '_', $type));
for ($i = 3; ($i < sizeof($targetPathParts) - 1); $i += 2) {
$urlParameters[] = [
'name' => $targetPathParts[$i],
'value' => $targetPathParts[$i + 1]
];
}

return $urlParameters;
}
}
16 changes: 13 additions & 3 deletions app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
# Copyright © Magento, Inc. All rights reserved.
# See COPYING.txt for license details.

type EntityUrl @doc(description: "EntityUrl is an output object containing the `id`, `relative_url`, and `type` attributes") {
type EntityUrl @doc(description: "EntityUrl is an output object containing the `id`, `canonical_url`, and `type` attributes") {
id: Int @doc(description: "The ID assigned to the object associated with the specified url. This could be a product ID, category ID, or page ID.")
relative_url: String @doc(description: "The internal relative URL. If the specified url is a redirect, the query returns the redirected URL, not the original.")
canonical_url: String @doc(description: "The internal relative URL. If the specified url is a redirect, the query returns the redirected URL, not the original.")
type: UrlRewriteEntityTypeEnum @doc(description: "One of PRODUCT, CATEGORY, or CMS_PAGE.")
}

type Query {
urlResolver(url: String!): EntityUrl @resolver(class: "Magento\\UrlRewriteGraphQl\\Model\\Resolver\\UrlRewrite") @doc(description: "The urlResolver query returns the relative URL for a specified product, category or CMS page")
urlResolver(url: String!): EntityUrl @resolver(class: "Magento\\UrlRewriteGraphQl\\Model\\Resolver\\EntityUrl") @doc(description: "The urlResolver query returns the relative URL for a specified product, category or CMS page")
}

enum UrlRewriteEntityTypeEnum {
}

type UrlRewrite @doc(description: "The object contains URL rewrite details") {
url: String @doc(description: "Request URL")
parameters: [HttpQueryParameter] @doc(description: "Request parameters")
}

type HttpQueryParameter @doc(description: "The object details of target path parameters") {
name: String @doc(description: "Parameter name")
value: String @doc(description: "Parameter value")
}
Loading