Skip to content
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
4 changes: 0 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ jobs:
- name: Run code style check
run: composer run-script check-cs -- --format=checkstyle | cs2pr

rector:
name: Run rector
uses: ibexa/gh-workflows/.github/workflows/rector.yml@main

tests:
name: Unit & integration tests
runs-on: "ubuntu-24.04"
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/rector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Rector PHP

on:
push:
branches:
- main
- '[0-9]+.[0-9]+'
pull_request: ~

jobs:
rector:
name: Run rector
runs-on: "ubuntu-22.04"
strategy:
matrix:
php:
- '8.3'
steps:
- uses: actions/checkout@v5

- uses: ibexa/gh-workflows/actions/composer-install@main
with:
gh-client-id: ${{ secrets.AUTOMATION_CLIENT_ID }}
gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }}

- name: Run rector
run: vendor/bin/rector process --dry-run --ansi
6 changes: 0 additions & 6 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,6 @@ parameters:
count: 1
path: src/lib/Input/FieldTypeParser.php

-
message: '#^Method Ibexa\\Rest\\Input\\Handler\\Json\:\:convert\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/lib/Input/Handler/Json.php

-
message: '#^Access to an undefined property DOMNode\:\:\$data\.$#'
identifier: property.notFound
Expand Down
2 changes: 2 additions & 0 deletions src/bundle/DependencyInjection/IbexaRestExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
$loader->load('default_settings.yml');
$loader->load('serializer.yaml');
$loader->load('twig.yaml');
$loader->load('criteria.yaml');
$loader->load('sort_clauses.yaml');

$processor = new ConfigurationProcessor($container, 'ibexa.site_access.config');
$processor->mapConfigArray('rest_root_resources', $mergedConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"ViewInput": {
"identifier": "ContentTypeView",
"ContentTypeQuery": {
"limit": "10",
"offset": "1",
"Query": {
"ContentTypeIdCriterion": [1,2],
"ContentTypeIdentifierCriterion": "folder",
"IsSystemCriterion": true,
"ContentTypeGroupIdCriterion": 1,
"ContainsFieldDefinitionIdCriterion": 2
},
"SortClauses": {
"Identifier": "descending",
"Id": "ascending"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<ViewInput>
<identifier>ContentTypeView</identifier>
<ContentTypeQuery>
<limit>10</limit>
<offset>1</offset>
<Query>
<ContentTypeIdCriterion>1</ContentTypeIdCriterion>
<ContentTypeIdCriterion>2</ContentTypeIdCriterion>
<ContentTypeIdentifierCriterion>folder</ContentTypeIdentifierCriterion>
<IsSystemCriterion>true</IsSystemCriterion>
<ContentTypeGroupIdCriterion>1</ContentTypeGroupIdCriterion>
<ContainsFieldDefinitionIdCriterion>2</ContainsFieldDefinitionIdCriterion>
</Query>
<SortClauses>
<Identifier>descending</Identifier>
<Id>ascending</Id>
</SortClauses>
</ContentTypeQuery>
</ViewInput>
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,77 @@ schemas:
properties:
ContentTypeList:
$ref: "#/components/schemas/ContentTypeInfoList"
ContentTypeQuery:
description: This class represents a content type query.
type: object
properties:
limit:
description: The maximum number of results to return.
type: integer
offset:
description: The offset to start returning results from.
type: integer
Query:
description: An array of filters to apply to the query.
type: object
properties:
ContentTypeIdCriterion:
oneOf:
- type: array
items:
type: integer
- type: integer
ContentTypeIdentifierCriterion:
oneOf:
- type: array
items:
type: string
- type: string
IsSystemCriterion:
type: boolean
ContentTypeGroupIdCriterion:
oneOf:
- type: array
items:
type: integer
- type: integer
ContainsFieldDefinitionIdCriterion:
oneOf:
- type: array
items:
type: integer
- type: integer
SortClauses:
description: An array of sort clauses to apply to the query.
type: object
properties:
Id:
type: string
enum: [ ascending, descending ]
Identifier:
type: string
enum: [ ascending, descending ]
ContentTypeViewInput:
description: This class represents a content type view input.
xml:
name: ViewInput
type: object
required:
- identifier
- ContentTypeQuery
properties:
identifier:
description: The identifier of a view.
type: string
ContentTypeQuery:
$ref: "#/components/schemas/ContentTypeQuery"
ContentTypeViewInputWrapper:
type: object
required:
- ViewInput
properties:
ViewInput:
$ref: "#/components/schemas/ContentTypeViewInput"
Field:
description: This class represents a field of a content item.
type: object
Expand Down
40 changes: 40 additions & 0 deletions src/bundle/Resources/config/criteria.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
services:
_instanceof:
Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContentTypeCriterionInterface:
tags:
- 'ibexa.rest.content_type.criterion'

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\CriterionProcessor:
parent: Ibexa\Contracts\Rest\Input\Parser\Query\Criterion\BaseCriterionProcessor

Ibexa\Rest\Server\Input\Parser\ContentType\SortClause\SortClauseProcessor:
parent: Ibexa\Contracts\Rest\Input\Parser\Query\SortClause\BaseSortClauseProcessor

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContentTypeCriteriaRegistry:
arguments:
- !tagged_iterator ibexa.rest.content_type.criterion

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContentTypeId:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.ContentTypeId }

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContentTypeIdentifier:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.ContentTypeIdentifier }

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\IsSystem:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.IsSystem }

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContentTypeGroupId:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.ContentTypeGroupId }

Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\ContainsFieldDefinitionId:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.criterion.ContainsFieldDefinitionId }
15 changes: 15 additions & 0 deletions src/bundle/Resources/config/input_parsers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ services:
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.ContentTypeUpdate }

Ibexa\Rest\Server\Input\Parser\ContentType\RestViewInput:
parent: Ibexa\Rest\Server\Common\Parser
arguments:
$validator: '@validator'
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.ContentTypeViewInput }

Ibexa\Rest\Server\Input\Parser\ContentType\Query\ContentTypeQuery:
parent: Ibexa\Rest\Server\Common\Parser
arguments:
$criterionProcessor: '@Ibexa\Rest\Server\Input\Parser\ContentType\Criterion\CriterionProcessor'
$sortClauseProcessor: '@Ibexa\Rest\Server\Input\Parser\ContentType\SortClause\SortClauseProcessor'
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.ContentTypeQuery }

Ibexa\Rest\Server\Input\Parser\FieldDefinitionCreate:
parent: Ibexa\Rest\Server\Common\Parser
class: Ibexa\Rest\Server\Input\Parser\FieldDefinitionCreate
Expand Down
7 changes: 7 additions & 0 deletions src/bundle/Resources/config/routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,13 @@ ibexa.rest.list_content_types:
controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeListController::listContentTypes
methods: [GET]

ibexa.rest.content_types.view:
path: /content/types/view
methods: [ POST ]
controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeCreateViewController::createView
options:
expose: true

ibexa.rest.copy_content_type:
path: /content/types/{contentTypeId}
controller: Ibexa\Rest\Server\Controller\ContentType\ContentTypeCopyController::copyContentType
Expand Down
24 changes: 24 additions & 0 deletions src/bundle/Resources/config/sort_clauses.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
Ibexa\Rest\Server\Input\Parser\ContentType\SortClause\ContentTypeSortClausesRegistry:
arguments:
- !tagged_iterator ibexa.rest.content_type.sort_clause

ibexa.rest.input.parser.internal.sortclause.id:
parent: Ibexa\Rest\Server\Common\Parser
class: Ibexa\Rest\Server\Input\Parser\SortClause\DataKeyValueObjectClass
arguments:
$dataKey: 'Id'
$valueObjectClass: 'Ibexa\Contracts\Core\Repository\Values\ContentType\Query\SortClause\Id'
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.sortclause.Id }
- { name: ibexa.rest.content_type.sort_clause }

ibexa.rest.input.parser.internal.sortclause.identifier:
parent: Ibexa\Rest\Server\Common\Parser
class: Ibexa\Rest\Server\Input\Parser\SortClause\DataKeyValueObjectClass
arguments:
$dataKey: 'Identifier'
$valueObjectClass: 'Ibexa\Contracts\Core\Repository\Values\ContentType\Query\SortClause\Identifier'
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.internal.sortclause.Identifier }
- { name: ibexa.rest.content_type.sort_clause }
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Rest\Server\Controller\ContentType;

use ApiPlatform\Metadata\Post;
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
use ApiPlatform\OpenApi\Model;
use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Rest\Message;
use Ibexa\Rest\Server\Controller as RestController;
use Ibexa\Rest\Server\Values;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

#[Post(
uriTemplate: '/content/types/view',
extraProperties: [OpenApiFactory::OVERRIDE_OPENAPI_RESPONSES => false],
openapi: new Model\Operation(
summary: 'Filter content types',
description: 'Executes a query and returns a View including the results. The View input reflects the criteria model of the public PHP API.',
tags: [
'Type',
],
parameters: [
new Model\Parameter(
name: 'Accept',
in: 'header',
required: true,
description: 'The view in XML or JSON format.',
schema: [
'type' => 'string',
],
),
new Model\Parameter(
name: 'Content-Type',
in: 'header',
required: true,
description: 'The view input in XML or JSON format.',
schema: [
'type' => 'string',
],
),
],
requestBody: new Model\RequestBody(
content: new \ArrayObject([
'application/vnd.ibexa.api.ContentTypeViewInput+xml' => [
'schema' => [
'$ref' => '#/components/schemas/ContentTypeViewInput',
],
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeCreateView.xml.example',
],
'application/vnd.ibexa.api.ContentTypeViewInput+json' => [
'schema' => [
'$ref' => '#/components/schemas/ContentTypeViewInputWrapper',
],
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/content_type_id/POST/ContentTypeCreateView.xml.example',
],
]),
),
responses: [
Response::HTTP_OK => [
'content' => [
'application/vnd.ibexa.api.ContentTypeList+xml' => [
'schema' => [
'$ref' => '#/components/schemas/ContentTypeInfoList',
],
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.xml.example',
],
'application/vnd.ibexa.api.ContentTypeList+json' => [
'schema' => [
'$ref' => '#/components/schemas/ContentTypeInfoListWrapper',
],
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/content/types/GET/ContentTypeInfoList.json.example',
],
],
],
Response::HTTP_BAD_REQUEST => [
'description' => 'Error - the input does not match the input schema definition.',
],
],
),
)]
final class ContentTypeCreateViewController extends RestController
{
public function __construct(
protected readonly ContentTypeService $contentTypeService
) {
}

public function createView(Request $request): Values\ContentTypeList
{
/** @var \Ibexa\Rest\Server\Values\ContentTypeRestViewInput $viewInput */
$viewInput = $this->inputDispatcher->parse(
new Message(
['Content-Type' => $request->headers->get('Content-Type')],
$request->getContent()
)
);

$contentTypes = $this->contentTypeService->findContentTypes($viewInput->query);

return new Values\ContentTypeList(
$contentTypes->getContentTypes(),
'',
);
}
}
Loading
Loading