Loading src/Plugin/GraphQL/DataProducer/Entity/EntityQuery.php 0 → 100644 +195 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\graphql\GraphQL\Execution\FieldContext; /** * Builds and executes Drupal entity query. * * Example for mapping this dataproducer to the schema: * @code * $defaultSorting = [ * [ * 'field' => 'created', * 'direction' => 'DESC', * ], * ]; * $registry->addFieldResolver('Query', 'jobApplicationsByUserId', * $builder->compose( * $builder->fromArgument('id'), * $builder->callback(function ($uid) { * $conditions = [ * [ * 'field' => 'uid', * 'value' => [$uid], * ], * ]; * return $conditions; * }), * $builder->produce('entity_query', [ * 'type' => $builder->fromValue('node'), * 'conditions' => $builder->fromParent(), * 'offset' => $builder->fromArgument('offset'), * 'limit' => $builder->fromArgument('limit'), * 'language' => $builder->fromArgument('language'), * 'allowed_filters' => $builder->fromValue(['uid']), * 'bundles' => $builder->fromValue(['job_application']), * 'sorts' => $builder->fromArgumentWithDefaultValue('sorting', $defaultSorting), * ]), * $builder->produce('entity_load_multiple', [ * 'type' => $builder->fromValue('node'), * 'ids' => $builder->fromParent(), * ]), * ) * ); * @endcode * * @DataProducer( * id = "entity_query", * name = @Translation("Load entities"), * description = @Translation("Returns entity IDs for a given query"), * produces = @ContextDefinition("string", * label = @Translation("Entity IDs"), * multiple = TRUE * ), * consumes = { * "type" = @ContextDefinition("string", * label = @Translation("Entity type") * ), * "limit" = @ContextDefinition("integer", * label = @Translation("Limit"), * required = FALSE, * default_value = 10 * ), * "offset" = @ContextDefinition("integer", * label = @Translation("Offset"), * required = FALSE, * default_value = 0 * ), * "owned_only" = @ContextDefinition("boolean", * label = @Translation("Query only owned entities"), * required = FALSE, * default_value = FALSE * ), * "conditions" = @ContextDefinition("any", * label = @Translation("Conditions"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "allowed_filters" = @ContextDefinition("string", * label = @Translation("Allowed filters"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "languages" = @ContextDefinition("string", * label = @Translation("Entity languages"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "bundles" = @ContextDefinition("any", * label = @Translation("Entity bundles"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "access" = @ContextDefinition("boolean", * label = @Translation("Check access"), * required = FALSE, * default_value = TRUE * ), * "sorts" = @ContextDefinition("any", * label = @Translation("Sorts"), * multiple = TRUE, * default_value = {}, * required = FALSE * ) * } * ) */ class EntityQuery extends EntityQueryBase { /** * The default maximum number of items to be capped to prevent DDOS attacks. */ const MAX_ITEMS = 100; /** * Resolves the entity query. * * @param string $type * Entity type. * @param int $limit * Maximum number of queried entities. * @param int $offset * Offset to start with. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param array $sorts * List of sorts. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return array * The list of ids that match this query. * * @throws \GraphQL\Error\UserError * No bundles defined for given entity type. */ public function resolve(string $type, int $limit, int $offset, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, array $sorts, FieldContext $context): array { $query = $this->buildBaseEntityQuery( $type, $ownedOnly, $conditions, $allowedFilters, $languages, $bundles, $access, $context ); // Make sure offset is zero or positive. $offset = max($offset, 0); // Make sure limit is positive and cap the max items to prevent DDOS // attacks. if ($limit <= 0) { $limit = 10; } $limit = min($limit, self::MAX_ITEMS); // Apply offset and limit. $query->range($offset, $limit); // Add sorts. foreach ($sorts as $sort) { if (!empty($sort['field'])) { if (!empty($sort['direction']) && strtolower($sort['direction']) == 'desc') { $direction = 'DESC'; } else { $direction = 'ASC'; } $query->sort($sort['field'], $direction); } } $ids = $query->execute(); return $ids; } } src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php 0 → 100644 +141 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\graphql\GraphQL\Execution\FieldContext; use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase; use GraphQL\Error\UserError; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Base class to share code between entity query and entity query count. */ abstract class EntityQueryBase extends DataProducerPluginBase implements ContainerFactoryPluginInterface { /** * The entity type manager service. * * @var \Drupal\Core\Entity\EntityTypeManager */ protected $entityTypeManager; /** * The current user proxy. * * @var \Drupal\Core\Session\AccountProxyInterface */ protected $currentUser; /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('current_user') ); } /** * EntityLoad constructor. * * @param array $configuration * The plugin configuration array. * @param string $pluginId * The plugin id. * @param array $pluginDefinition * The plugin definition array. * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager * The entity type manager service. * @param \Drupal\Core\Session\AccountProxyInterface $current_user * The current user proxy. */ public function __construct( array $configuration, string $pluginId, array $pluginDefinition, EntityTypeManager $entityTypeManager, AccountProxyInterface $current_user ) { parent::__construct($configuration, $pluginId, $pluginDefinition); $this->entityTypeManager = $entityTypeManager; $this->currentUser = $current_user; } /** * Build base entity query which may be reused for count query as well. * * @param string $type * Entity type. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return \Drupal\Core\Entity\Query\QueryInterface * Base entity query. * * @throws \GraphQL\Error\UserError * No bundles defined for given entity type. */ protected function buildBaseEntityQuery(string $type, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, FieldContext $context): QueryInterface { $entity_type = $this->entityTypeManager->getStorage($type); $query = $entity_type->getQuery(); // Query only those entities which are owned by current user, if desired. if ($ownedOnly) { $query->condition('uid', $this->currentUser->id()); // Add user cacheable dependencies. $account = $this->currentUser->getAccount(); $context->addCacheableDependency($account); // Cache response per user to make sure the user related result is shown. $context->addCacheContexts(['user']); } // Ensure that desired access checking is performed on the query. $query->accessCheck($access); // Filter entities only of given bundles, if desired. if ($bundles) { $bundle_key = $entity_type->getEntityType()->getKey('bundle'); if (!$bundle_key) { throw new UserError('No bundles defined for given entity type.'); } $query->condition($bundle_key, $bundles, 'IN'); } // Filter entities by given languages, if desired. if ($languages) { $query->condition('langcode', $languages, 'IN'); } // Filter by given conditions. foreach ($conditions as $condition) { if (!in_array($condition['field'], $allowedFilters)) { throw new UserError("Field '{$condition['field']}' is not allowed as filter."); } $operation = $condition['operator'] ?? NULL; $query->condition($condition['field'], $condition['value'], $operation); } return $query; } } src/Plugin/GraphQL/DataProducer/Entity/EntityQueryCount.php 0 → 100644 +138 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\graphql\GraphQL\Execution\FieldContext; /** * Builds and executes Drupal entity query count. * * It supposed to be used along the entity query to get the total amount of * items. This is important for pagination when the total amount needs to be * known to derive the number of available pages. Otherwise the query works the * same way as entity query. Same filters are applied, just skips the offset and * limit, and turns the query into count query. * * Example for mapping this dataproducer to the schema: * @code * $defaultSorting = [ * [ * 'field' => 'created', * 'direction' => 'DESC', * ], * ]; * $registry->addFieldResolver('Query', 'jobApplicationsByUserIdCount', * $builder->compose( * $builder->fromArgument('id'), * $builder->callback(function ($uid) { * $conditions = [ * [ * 'field' => 'uid', * 'value' => [$uid], * ], * ]; * return $conditions; * }), * $builder->produce('entity_query_count', [ * 'type' => $builder->fromValue('node'), * 'conditions' => $builder->fromParent(), * 'offset' => $builder->fromArgument('offset'), * 'limit' => $builder->fromArgument('limit'), * 'language' => $builder->fromArgument('language'), * 'allowed_filters' => $builder->fromValue(['uid']), * 'bundles' => $builder->fromValue(['job_application']), * 'sorts' => $builder->fromArgumentWithDefaultValue('sorting', $defaultSorting), * ]) * ) * ); * @endcode * * @DataProducer( * id = "entity_query_count", * name = @Translation("Load entities"), * description = @Translation("Loads entities."), * produces = @ContextDefinition("integer", * label = @Translation("Total count of items queried by entity query."), * ), * consumes = { * "type" = @ContextDefinition("string", * label = @Translation("Entity type") * ), * "owned_only" = @ContextDefinition("boolean", * label = @Translation("Query only owned entities"), * required = FALSE, * default_value = FALSE * ), * "conditions" = @ContextDefinition("any", * label = @Translation("Conditions"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "allowed_filters" = @ContextDefinition("string", * label = @Translation("Allowed filters"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "languages" = @ContextDefinition("string", * label = @Translation("Entity languages"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "bundles" = @ContextDefinition("any", * label = @Translation("Entity bundles"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "access" = @ContextDefinition("boolean", * label = @Translation("Check access"), * required = FALSE, * default_value = TRUE * ) * } * ) */ class EntityQueryCount extends EntityQueryBase { /** * Resolves the entity query count. * * @param string $type * Entity type. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return int * Total count of items queried by entity query. */ public function resolve(string $type, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, FieldContext $context): int { $query = $this->buildBaseEntityQuery( $type, $ownedOnly, $conditions, $allowedFilters, $languages, $bundles, $access, $context ); return $query->count()->execute(); } } Loading
src/Plugin/GraphQL/DataProducer/Entity/EntityQuery.php 0 → 100644 +195 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\graphql\GraphQL\Execution\FieldContext; /** * Builds and executes Drupal entity query. * * Example for mapping this dataproducer to the schema: * @code * $defaultSorting = [ * [ * 'field' => 'created', * 'direction' => 'DESC', * ], * ]; * $registry->addFieldResolver('Query', 'jobApplicationsByUserId', * $builder->compose( * $builder->fromArgument('id'), * $builder->callback(function ($uid) { * $conditions = [ * [ * 'field' => 'uid', * 'value' => [$uid], * ], * ]; * return $conditions; * }), * $builder->produce('entity_query', [ * 'type' => $builder->fromValue('node'), * 'conditions' => $builder->fromParent(), * 'offset' => $builder->fromArgument('offset'), * 'limit' => $builder->fromArgument('limit'), * 'language' => $builder->fromArgument('language'), * 'allowed_filters' => $builder->fromValue(['uid']), * 'bundles' => $builder->fromValue(['job_application']), * 'sorts' => $builder->fromArgumentWithDefaultValue('sorting', $defaultSorting), * ]), * $builder->produce('entity_load_multiple', [ * 'type' => $builder->fromValue('node'), * 'ids' => $builder->fromParent(), * ]), * ) * ); * @endcode * * @DataProducer( * id = "entity_query", * name = @Translation("Load entities"), * description = @Translation("Returns entity IDs for a given query"), * produces = @ContextDefinition("string", * label = @Translation("Entity IDs"), * multiple = TRUE * ), * consumes = { * "type" = @ContextDefinition("string", * label = @Translation("Entity type") * ), * "limit" = @ContextDefinition("integer", * label = @Translation("Limit"), * required = FALSE, * default_value = 10 * ), * "offset" = @ContextDefinition("integer", * label = @Translation("Offset"), * required = FALSE, * default_value = 0 * ), * "owned_only" = @ContextDefinition("boolean", * label = @Translation("Query only owned entities"), * required = FALSE, * default_value = FALSE * ), * "conditions" = @ContextDefinition("any", * label = @Translation("Conditions"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "allowed_filters" = @ContextDefinition("string", * label = @Translation("Allowed filters"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "languages" = @ContextDefinition("string", * label = @Translation("Entity languages"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "bundles" = @ContextDefinition("any", * label = @Translation("Entity bundles"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "access" = @ContextDefinition("boolean", * label = @Translation("Check access"), * required = FALSE, * default_value = TRUE * ), * "sorts" = @ContextDefinition("any", * label = @Translation("Sorts"), * multiple = TRUE, * default_value = {}, * required = FALSE * ) * } * ) */ class EntityQuery extends EntityQueryBase { /** * The default maximum number of items to be capped to prevent DDOS attacks. */ const MAX_ITEMS = 100; /** * Resolves the entity query. * * @param string $type * Entity type. * @param int $limit * Maximum number of queried entities. * @param int $offset * Offset to start with. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param array $sorts * List of sorts. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return array * The list of ids that match this query. * * @throws \GraphQL\Error\UserError * No bundles defined for given entity type. */ public function resolve(string $type, int $limit, int $offset, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, array $sorts, FieldContext $context): array { $query = $this->buildBaseEntityQuery( $type, $ownedOnly, $conditions, $allowedFilters, $languages, $bundles, $access, $context ); // Make sure offset is zero or positive. $offset = max($offset, 0); // Make sure limit is positive and cap the max items to prevent DDOS // attacks. if ($limit <= 0) { $limit = 10; } $limit = min($limit, self::MAX_ITEMS); // Apply offset and limit. $query->range($offset, $limit); // Add sorts. foreach ($sorts as $sort) { if (!empty($sort['field'])) { if (!empty($sort['direction']) && strtolower($sort['direction']) == 'desc') { $direction = 'DESC'; } else { $direction = 'ASC'; } $query->sort($sort['field'], $direction); } } $ids = $query->execute(); return $ids; } }
src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php 0 → 100644 +141 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\graphql\GraphQL\Execution\FieldContext; use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase; use GraphQL\Error\UserError; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Base class to share code between entity query and entity query count. */ abstract class EntityQueryBase extends DataProducerPluginBase implements ContainerFactoryPluginInterface { /** * The entity type manager service. * * @var \Drupal\Core\Entity\EntityTypeManager */ protected $entityTypeManager; /** * The current user proxy. * * @var \Drupal\Core\Session\AccountProxyInterface */ protected $currentUser; /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('current_user') ); } /** * EntityLoad constructor. * * @param array $configuration * The plugin configuration array. * @param string $pluginId * The plugin id. * @param array $pluginDefinition * The plugin definition array. * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager * The entity type manager service. * @param \Drupal\Core\Session\AccountProxyInterface $current_user * The current user proxy. */ public function __construct( array $configuration, string $pluginId, array $pluginDefinition, EntityTypeManager $entityTypeManager, AccountProxyInterface $current_user ) { parent::__construct($configuration, $pluginId, $pluginDefinition); $this->entityTypeManager = $entityTypeManager; $this->currentUser = $current_user; } /** * Build base entity query which may be reused for count query as well. * * @param string $type * Entity type. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return \Drupal\Core\Entity\Query\QueryInterface * Base entity query. * * @throws \GraphQL\Error\UserError * No bundles defined for given entity type. */ protected function buildBaseEntityQuery(string $type, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, FieldContext $context): QueryInterface { $entity_type = $this->entityTypeManager->getStorage($type); $query = $entity_type->getQuery(); // Query only those entities which are owned by current user, if desired. if ($ownedOnly) { $query->condition('uid', $this->currentUser->id()); // Add user cacheable dependencies. $account = $this->currentUser->getAccount(); $context->addCacheableDependency($account); // Cache response per user to make sure the user related result is shown. $context->addCacheContexts(['user']); } // Ensure that desired access checking is performed on the query. $query->accessCheck($access); // Filter entities only of given bundles, if desired. if ($bundles) { $bundle_key = $entity_type->getEntityType()->getKey('bundle'); if (!$bundle_key) { throw new UserError('No bundles defined for given entity type.'); } $query->condition($bundle_key, $bundles, 'IN'); } // Filter entities by given languages, if desired. if ($languages) { $query->condition('langcode', $languages, 'IN'); } // Filter by given conditions. foreach ($conditions as $condition) { if (!in_array($condition['field'], $allowedFilters)) { throw new UserError("Field '{$condition['field']}' is not allowed as filter."); } $operation = $condition['operator'] ?? NULL; $query->condition($condition['field'], $condition['value'], $operation); } return $query; } }
src/Plugin/GraphQL/DataProducer/Entity/EntityQueryCount.php 0 → 100644 +138 −0 Original line number Diff line number Diff line <?php namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity; use Drupal\graphql\GraphQL\Execution\FieldContext; /** * Builds and executes Drupal entity query count. * * It supposed to be used along the entity query to get the total amount of * items. This is important for pagination when the total amount needs to be * known to derive the number of available pages. Otherwise the query works the * same way as entity query. Same filters are applied, just skips the offset and * limit, and turns the query into count query. * * Example for mapping this dataproducer to the schema: * @code * $defaultSorting = [ * [ * 'field' => 'created', * 'direction' => 'DESC', * ], * ]; * $registry->addFieldResolver('Query', 'jobApplicationsByUserIdCount', * $builder->compose( * $builder->fromArgument('id'), * $builder->callback(function ($uid) { * $conditions = [ * [ * 'field' => 'uid', * 'value' => [$uid], * ], * ]; * return $conditions; * }), * $builder->produce('entity_query_count', [ * 'type' => $builder->fromValue('node'), * 'conditions' => $builder->fromParent(), * 'offset' => $builder->fromArgument('offset'), * 'limit' => $builder->fromArgument('limit'), * 'language' => $builder->fromArgument('language'), * 'allowed_filters' => $builder->fromValue(['uid']), * 'bundles' => $builder->fromValue(['job_application']), * 'sorts' => $builder->fromArgumentWithDefaultValue('sorting', $defaultSorting), * ]) * ) * ); * @endcode * * @DataProducer( * id = "entity_query_count", * name = @Translation("Load entities"), * description = @Translation("Loads entities."), * produces = @ContextDefinition("integer", * label = @Translation("Total count of items queried by entity query."), * ), * consumes = { * "type" = @ContextDefinition("string", * label = @Translation("Entity type") * ), * "owned_only" = @ContextDefinition("boolean", * label = @Translation("Query only owned entities"), * required = FALSE, * default_value = FALSE * ), * "conditions" = @ContextDefinition("any", * label = @Translation("Conditions"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "allowed_filters" = @ContextDefinition("string", * label = @Translation("Allowed filters"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "languages" = @ContextDefinition("string", * label = @Translation("Entity languages"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "bundles" = @ContextDefinition("any", * label = @Translation("Entity bundles"), * multiple = TRUE, * required = FALSE, * default_value = {} * ), * "access" = @ContextDefinition("boolean", * label = @Translation("Check access"), * required = FALSE, * default_value = TRUE * ) * } * ) */ class EntityQueryCount extends EntityQueryBase { /** * Resolves the entity query count. * * @param string $type * Entity type. * @param bool $ownedOnly * Query only entities owned by current user. * @param array $conditions * List of conditions to filter the entities. * @param array $allowedFilters * List of fields to be used in conditions to restrict access to data. * @param string[] $languages * Languages for queried entities. * @param string[] $bundles * List of bundles to be filtered. * @param bool $access * Whether entity query should check access. * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context * The caching context related to the current field. * * @return int * Total count of items queried by entity query. */ public function resolve(string $type, bool $ownedOnly, array $conditions, array $allowedFilters, array $languages, array $bundles, bool $access, FieldContext $context): int { $query = $this->buildBaseEntityQuery( $type, $ownedOnly, $conditions, $allowedFilters, $languages, $bundles, $access, $context ); return $query->count()->execute(); } }