Skip to content

Commit

Permalink
chore: More adjustments to work with DefaultMockup.
Browse files Browse the repository at this point in the history
  • Loading branch information
das-peter committed Aug 15, 2024
1 parent 1b3ca7d commit 0848190
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\DataHubBundle\GraphQL\Service;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\DefaultMockup;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\Element\ElementInterface;
Expand Down Expand Up @@ -74,8 +75,9 @@ public function resolve($value = null, $args = [], $context = [], ResolveInfo $r
if ($value instanceof BaseDescriptor) {
$relation = \Pimcore\Bundle\DataHubBundle\GraphQL\Service::resolveValue($value, $this->fieldDefinition, $this->attribute, $args);

if ($relation instanceof ElementInterface) {
if (!WorkspaceHelper::checkPermission($relation, 'read')) {
if ($relation instanceof ElementInterface || $relation instanceof DefaultMockup) {
$type = ($relation instanceof DefaultMockup) ? 'object' : '';
if (!WorkspaceHelper::checkPermission($relation, 'read', $type)) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\DataHubBundle\GraphQL\Service;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\DefaultMockup;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\Element\AbstractElement;

Expand Down Expand Up @@ -74,7 +75,8 @@ public function resolve($value = null, $args = [], $context = [], ResolveInfo $r
if ($relations) {
/** @var AbstractElement $relation */
foreach ($relations as $relation) {
if (!WorkspaceHelper::checkPermission($relation, 'read')) {
$type = ($relation instanceof DefaultMockup) ? 'object' : '';
if (!WorkspaceHelper::checkPermission($relation, 'read', $type)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\DataHubBundle\GraphQL\Service;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\DefaultMockup;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\Data\ElementMetadata;
Expand Down Expand Up @@ -76,7 +77,8 @@ public function resolve($value = null, $args = [], $context = [], ResolveInfo $r
/** @var ElementMetadata $relation */
foreach ($relations as $relation) {
$element = $relation->getElement();
if (!WorkspaceHelper::checkPermission($element, 'read')) {
$type = ($element instanceof DefaultMockup) ? 'object' : '';
if (!WorkspaceHelper::checkPermission($element, 'read', $type)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,7 @@ public function resolve($value = null, $args = [], $context = [], ResolveInfo $r
// Explicitly set the type of the mockup object because
// these don't have the matching class instance for
// auto-detect.
$type = '';
if ($relation instanceof DefaultMockup) {
$type = $relation->getType();
}
$type = ($relation instanceof DefaultMockup) ? 'object' : '';
if (!WorkspaceHelper::checkPermission($relation, 'read', $type)) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\DataHubBundle\GraphQL\Service;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\DefaultMockup;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\DataObject\Data\ObjectMetadata;

Expand Down Expand Up @@ -75,7 +76,8 @@ public function resolve($value = null, $args = [], $context = [], ResolveInfo $r
/** @var ObjectMetadata $relation */
foreach ($relations as $relation) {
$element = $relation->getElement();
if (!WorkspaceHelper::checkPermission($element, 'read')) {
$type = ($element instanceof DefaultMockup) ? 'object' : '';
if (!WorkspaceHelper::checkPermission($element, 'read', $type)) {
continue;
}

Expand Down
51 changes: 2 additions & 49 deletions src/GraphQL/FieldHelper/DataObjectFieldHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -370,59 +370,12 @@ public function doExtractData(FieldNode $ast, &$data, $container, $args, $contex
if ($this->skipField($container, $astName)) {
return;
}

// example for http://webonyx.github.io/graphql-php/error-handling/
// throw new MySafeException("fieldhelper", "TBD customized error message");

$getter = 'get' . ucfirst($astName);

$isLocalizedField = false;
$containerDefinition = null;

// This reflection object is used to determine if the getter can be used.
// $container isn't used directly in order to allow specialized handling
// of mock objects and other placeholders which act transparently but
// don't implement the getters themselves.
$methodCheckClass = new \ReflectionClass($container);
$skipMethodCallCheck = false;
// Adjust meta data for data handling on type of the data container.
switch (true) {
case $container instanceof Concrete:
$containerDefinition = $container->getClass();
break;

case $container instanceof AbstractData:
case $container instanceof \Pimcore\Model\DataObject\Objectbrick\Data\AbstractData:
$containerDefinition = $container->getDefinition();
break;

// All default indexers implement o_classId - access it directly to
// load class definition and with it use the model loader to fetch
// the actual implementing class for further reflection.
case $container instanceof DefaultMockup:
if (($mockClassId = $container->getParam('o_classId'))) {
$containerDefinition = ClassDefinition::getById($mockClassId);
// Unfortunately there's no API for this so we re-implement
// what \Pimcore\Model\DataObject\AbstractObject::getById()
// does.
$baseClassName = 'Pimcore\\Model\\DataObject\\' . ucfirst($containerDefinition->getName());
$className = $this->modelFactory->getClassNameFor($baseClassName);
$methodCheckClass = new \ReflectionClass($className);
} else {
$skipMethodCallCheck = true;
}
break;
}

if ($containerDefinition) {
/** @var Data\Localizedfields|null $lfDefs */
$lfDefs = $containerDefinition->getFieldDefinition('localizedfields');
if ($lfDefs && $lfDefs->getFieldDefinition($astName)) {
$isLocalizedField = true;
}
}

if (($methodCheckClass->hasMethod($getter) && $methodCheckClass->getMethod($getter)->isPublic()) || $skipMethodCallCheck) {
if ($this->getGraphQlService()::checkContainerMethodExists($container, $getter)) {
$isLocalizedField = $this->getGraphQlService()::isLocalizedField($container, $astName);
if ($isLocalizedField) {
// defer it
$data[$astName] = function ($source, $args, $context, ResolveInfo $info) use (
Expand Down
5 changes: 3 additions & 2 deletions src/GraphQL/RelationHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@
namespace Pimcore\Bundle\DataHubBundle\GraphQL;

use GraphQL\Type\Definition\ResolveInfo;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\DefaultMockup;
use Pimcore\Model\Element\ElementInterface;

class RelationHelper
{
/**
* @param ElementInterface $relation
* @param ElementInterface|DefaultMockup $relation
* @param Service $graphQlService
* @param array $args
* @param array $context
* @param ResolveInfo $resolveInfo
*
* @return ElementDescriptor
*/
public static function processRelation(ElementInterface $relation, Service $graphQlService, $args, $context, ResolveInfo $resolveInfo)
public static function processRelation(ElementInterface|DefaultMockup $relation, Service $graphQlService, $args, $context, ResolveInfo $resolveInfo)
{
$data = new ElementDescriptor($relation);
$graphQlService->extractData($data, $relation, $args, $context, $resolveInfo);
Expand Down
99 changes: 89 additions & 10 deletions src/GraphQL/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ public static function setValue($object, $attribute, $callback)

return $result;
}
} elseif (method_exists($container, $setter)) {
} elseif (static::checkContainerMethodExists($container, $setter)) {
$result = $callback($container, $setter);
}

Expand Down Expand Up @@ -1077,7 +1077,7 @@ public static function resolveValue(BaseDescriptor $descriptor, Data $fieldDefin

return $value;
}
} elseif (method_exists($container, $getter)) {
} elseif (static::checkContainerMethodExists($container, $getter)) {
$isLocalizedField = self::isLocalizedField($container, $fieldDefinition->getName());
if ($isLocalizedField) {
$result = $container->$getter($args['language'] ?? null);
Expand Down Expand Up @@ -1124,15 +1124,9 @@ public static function resolveCachedValue($value, $resolveInfo = null)
*
* @return bool
*/
private static function isLocalizedField($container, $fieldName): bool
public static function isLocalizedField($container, $fieldName): bool
{
$containerDefinition = null;

if ($container instanceof Concrete) {
$containerDefinition = $container->getClass();
} elseif ($container instanceof AbstractData) {
$containerDefinition = $container->getDefinition();
}
$containerDefinition = static::getContainerClassDefinition($container);

if ($containerDefinition) {
/** @var Data\Localizedfields|null $lfDefs */
Expand Down Expand Up @@ -1214,4 +1208,89 @@ public function querySchemaEnabled(string $type)

return $enabled;
}

/**
* Checks if a container has a given method.
*
* This works with DefaultMockup objects too that's why it's so overly
* complex. DefaultMockup objects will use the class definition of the
* mocked object to determine which model class has to be checked for the
* method.
*
* @param object $container
* @param string $method
*
* @return bool
* @throws \ReflectionException
*/
public static function checkContainerMethodExists(object $container, string $method): bool
{
// This reflection object is used to determine if the getter can be used.
// $container isn't used directly in order to allow specialized handling
// of mock objects and other placeholders which act transparently but
// don't implement the getters themselves.
$methodCheckClass = new \ReflectionClass($container);
$skipMethodCallCheck = false;

// Adjust meta data for data handling on type of the data container.
$containerDefinition = static::getContainerClassDefinition($container);
if ($container instanceof DefaultMockup) {
if ($containerDefinition) {
// Unfortunately there's no API for this so we re-implement
// what \Pimcore\Model\DataObject\AbstractObject::getById()
// does.
$baseClassName = 'Pimcore\\Model\\DataObject\\' . ucfirst($containerDefinition->getName());
// @TODO figure out a nicer way to handle this. Really naughty
// to call kernel directly - but static doesn't have DI.
/** @var self $service */
$service = \Pimcore::getKernel()->getContainer()->get(static::class);
$className = $service->getModelFactory()->getClassNameFor($baseClassName);
$methodCheckClass = new \ReflectionClass($className);
} else {
$skipMethodCallCheck = true;
}
}
if (
(
$methodCheckClass->hasMethod($method)
&& $methodCheckClass->getMethod($method)->isPublic()
)
|| $skipMethodCallCheck
) {
return true;
}
return false;
}

/**
* Returns the ClassDefinition of a container - works with DefaultMockup
* objects too.
*
* @param object $container
*
* @return ClassDefinition|null
* @throws \Exception
*/
public static function getContainerClassDefinition(object $container): ?ClassDefinition
{
// Adjust meta data for data handling on type of the data container.
switch (true) {
case $container instanceof Concrete:
return $container->getClass();

case $container instanceof \Pimcore\Model\DataObject\Fieldcollection\Data\AbstractData:
case $container instanceof \Pimcore\Model\DataObject\Objectbrick\Data\AbstractData:
return $container->getDefinition();

// All default indexers implement o_classId - access it directly to
// load class definition and with it use the model loader to fetch
// the actual implementing class for further reflection.
case $container instanceof DefaultMockup:
if (($mockClassId = $container->getParam('o_classId'))) {
return ClassDefinition::getById($mockClassId);
}
break;
}
return null;
}
}

0 comments on commit 0848190

Please sign in to comment.