Skip to content

Managing content

Locations

You can manage locations that hold content using LocationService.

Location REST API

To learn how to manage locations using the REST API, see REST API reference.

Adding a new location to a content item

Every published content item must have at least one location. One content item can have more that one location, which means it's presented in more than one place in the content tree.

Creating a new location, like creating content, requires using a struct, because a location value object is read-only.

To add a new location to existing content you need to create a LocationCreateStruct and pass it to the LocationService::createLocation method:

1
2
3
4
        $locationCreateStruct = $this->locationService->newLocationCreateStruct($parentLocationId);

        $contentInfo = $this->contentService->loadContentInfo($contentId);
        $newLocation = $this->locationService->createLocation($contentInfo, $locationCreateStruct);

LocationCreateStruct must receive the parent location ID. It sets the parentLocationId property of the new location.

You can also provide other properties for the location, otherwise they're set to their defaults:

1
2
        $locationCreateStruct->priority = 500;
        $locationCreateStruct->hidden = true;

Changing the main location

When a content item has more that one location, one location is always considered the main one. You can change the main location using ContentService, by updating the ContentInfo with a ContentUpdateStruct that sets the new main location:

1
2
3
4
        $contentUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
        $contentUpdateStruct->mainLocationId = $locationId;

        $this->contentService->updateContentMetadata($contentInfo, $contentUpdateStruct);

Hiding and revealing locations

To hide or reveal (unhide) a location you need to make use of LocationService::hideLocation or LocationService::unhideLocation:

1
2
3
        $this->locationService->hideLocation($location);

        $this->locationService->unhideLocation($location);

See location visibility for detailed information on the behavior of visible and hidden Locations.

Deleting a location

You can remove a location either by deleting it, or sending it to Trash.

Deleting makes use of LocationService::deleteLocation(). It permanently deletes the location, together with its whole subtree.

Content which has only this one location is permanently deleted as well. Content which has more locations is still available in its other locations. If you delete the main location of a content item that has more locations, another location becomes the main one.

1
2
3
        $location = $this->locationService->loadLocation($locationId);

        $this->locationService->deleteLocation($location);

To send the location and its subtree to Trash, use TrashService::trash. Items in Trash can be later restored, or deleted permanently.

1
        $this->trashService->trash($location);

Moving and copying a subtree

You can move a location with its whole subtree using LocationService::moveSubtree:

1
2
3
        $sourceLocation = $this->locationService->loadLocation($locationId);
        $targetLocation = $this->locationService->loadLocation($targetLocationId);
        $this->locationService->moveSubtree($sourceLocation, $targetLocation);

LocationService::copySubtree is used in the same way, but it copies the location and its subtree instead of moving it.

Tip

To copy a subtree you can also make use of the built-in copy-subtree command: bin/console ibexa:copy-subtree <sourceLocationId> <targetLocationId>.

Note

Copy subtree limit only applies to operations in the back office. It's ignored when copying subtrees using the PHP API.

Trash

Trash REST API

To learn how to manage Trash using the REST API, see REST API reference.

To empty the Trash (remove all locations in Trash), use TrashService::emptyTrash, which takes no arguments.

You can recover an item from Trash using TrashService::recover. You must provide the method with the ID of the object in Trash. Trash location is identical to the origin location of the object.

1
            $this->trashService->recover($trashItem, $newParent);

The content item is restored under its previous location. You can also provide a different location to restore in as a second argument:

1
2
$newParent = $this->locationService->loadLocation($location);
$this->trashService->recover($trashItem, $newParent);

You can also search through Trash items and sort the results using several public PHP API Search Criteria and Sort Clauses that have been exposed for TrashService queries. For more information, see Searching in trash.

Content types

Content type REST API

To learn how to manage content types using the REST API, see REST API reference for content types and content type groups.

Adding content types

To operate on content types, you need to make use of ContentTypeService.

Adding a new content type, like creating content, must happen with the use of a struct, because a content type value object is read-only. In this case you use ContentTypeCreateStruct.

A content type must have at least one name, in the main language, and at least one field definition.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
        $contentTypeCreateStruct = $this->contentTypeService->newContentTypeCreateStruct($contentTypeIdentifier);
        $contentTypeCreateStruct->mainLanguageCode = 'eng-GB';
        $contentTypeCreateStruct->nameSchema = '<name>';

        $contentTypeCreateStruct->names = [
            'eng-GB' => $contentTypeIdentifier,
        ];

        $titleFieldCreateStruct = $this->contentTypeService->newFieldDefinitionCreateStruct('name', 'ibexa_string');

        $contentTypeCreateStruct->addFieldDefinition($titleFieldCreateStruct);

        $contentTypeDraft = $this->contentTypeService->createContentType(
            $contentTypeCreateStruct,
            [$contentTypeGroup]
        );

        $this->contentTypeService->publishContentTypeDraft($contentTypeDraft);

You can specify more details of the field definition in the create struct, for example:

1
2
3
4
5
6
7
8
        $titleFieldCreateStruct = $this->contentTypeService->newFieldDefinitionCreateStruct('name', 'ibexa_string');
        $titleFieldCreateStruct->names = ['eng-GB' => 'Name'];
        $titleFieldCreateStruct->descriptions = ['eng-GB' => 'The name'];
        $titleFieldCreateStruct->fieldGroup = 'content';
        $titleFieldCreateStruct->position = 10;
        $titleFieldCreateStruct->isTranslatable = true;
        $titleFieldCreateStruct->isRequired = true;
        $titleFieldCreateStruct->isSearchable = true;

Copying content types

To copy a content type, use ContentTypeService::copyContentType:

1
2
3
            $contentTypeToCopy = $this->contentTypeService->loadContentTypeByIdentifier($contentTypeIdentifier);

            $copy = $this->contentTypeService->copyContentType($contentTypeToCopy);

The copy is automatically getting an identifier based on the original content type identifier and the copy's ID, for example: copy_of_folder_21.

To change the identifier of the copy, use a ContentTypeUpdateStruct:

1
2
3
4
5
6
            $copy = $this->contentTypeService->copyContentType($contentTypeToCopy);
            $copyDraft = $this->contentTypeService->createContentTypeDraft($copy);
            $copyUpdateStruct = $this->contentTypeService->newContentTypeUpdateStruct();
            $copyUpdateStruct->identifier = $copyIdentifier;
            $copyUpdateStruct->names = ['eng-GB' => $copyIdentifier];
            $this->contentTypeService->updateContentTypeDraft($copyDraft, $copyUpdateStruct);

Finding and filtering content types

You can find content types that match specific criteria by using the ContentTypeService::findContentTypes() method. This method accepts a ContentTypeQuery object that supports filtering and sorting by IDs, identifiers, group membership, and other criteria.

Criterions, sort clauses and REST APIs

For a full list of available criterions and sort clauses that you can use when finding and filtering content types, see Content Type Search Criteria and Content Type Search Sort Clauses references.

For the REST API, see Filter content types.

The following example shows how you can use the criteria to find content types:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php declare(strict_types=1);

namespace App\Command;

use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\ContentTypeQuery;
use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\Criterion;
use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\SortClause;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(
    name: 'doc:find_content_types',
    description: 'Lists content types that match specific criteria.'
)]
class FindContentTypeCommand extends Command
{
    public function __construct(private readonly ContentTypeService $contentTypeService)
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Find content types from the "Content" group that contains a specific field definition (in this case, a "Body" field).
        $query = new ContentTypeQuery(
            new Criterion\LogicalAnd([
                new Criterion\ContentTypeGroupId([1]),
                new Criterion\ContainsFieldDefinitionId([121]),
            ]),
            [
                new SortClause\Id(),
                new SortClause\Identifier(),
                new SortClause\Name(),
            ]
        );

        $searchResult = $this->contentTypeService->findContentTypes($query);

        $output->writeln('Found ' . $searchResult->getTotalCount() . ' content type(s):');

        foreach ($searchResult->getContentTypes() as $contentType) {
            $output->writeln(sprintf(
                '- [%d] %s (identifier: %s)',
                $contentType->id,
                $contentType->getName(),
                $contentType->identifier
            ));
        }

        return Command::SUCCESS;
    }
}

Query parameters

When constructing a ContentTypeQuery, you can pass the following parameters:

  • ?CriterionInterface $criterion = null — a filter to apply (use one or a combination of the criterions above)

  • array $sortClauses = [] — list of sort clauses to order the results

  • int $offset = 0 — starting offset (for pagination)

  • int $limit = 25 — maximum number of results to return

Calendar events

You can handle the calendar using CalendarServiceInterface (Ibexa\Contracts\Calendar\CalendarServiceInterface).

Calendar REST API

To learn how to manage the Calendar using the REST API, see REST API reference.

Getting events

To get a list of events for a specified time period, use the CalendarServiceInterface::getEvents method. You need to provide the method with an EventQuery, which takes a date range and a count as the minimum of parameters:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
        $dateFrom = new \DateTimeImmutable('2023-01-01T10:00:00+00:00');
        $dateTo = new \DateTimeImmutable('2023-12-31T10:0:00+00:00');
        $dateRange = new Calendar\DateRange($dateFrom, $dateTo);

        $eventQuery = new Calendar\EventQuery($dateRange, 10);

        $eventList = $this->calendarService->getEvents($eventQuery);

        foreach ($eventList as $event) {
            $output->writeln($event->getName() . '; date: ' . $event->getDateTime()->format('T Y-m-d H:i:s'));
        }

You can also get the first and last event in the list by using the first() and last() methods of an EventCollection (Ibexa\Contracts\Calendar\EventCollection):

1
2
        $eventCollection = $eventList->getEvents();
        $output->writeln('First event: ' . $eventCollection->first()->getName() . '; date: ' . $eventCollection->first()->getDateTime()->format('T Y-m-d H:i:s'));

You can process the events in a collection using the find(Closure $predicate), filter(Closure $predicate), map(Closure $callback) or slice(int $offset, ?int $length = null) methods of EventCollection, for example:

1
2
3
4
        $newCollection = $eventCollection->slice(3, 5);
        foreach ($newCollection as $event) {
            $output->writeln('New collection: ' . $event->getName() . '; date: ' . $event->getDateTime()->format('T Y-m-d H:i:s'));
        }

Performing calendar actions

You can perform a calendar action (for example, reschedule or unschedule calendar events) using the CalendarServiceInterface::executeAction() method. You must pass an Ibexa\Contracts\Calendar\EventAction\EventActionContext instance as argument. EventActionContext defines events on which the action is performed, and action-specific parameters, for example, a new date:

1
2
3
4
        $newDate = new \DateTimeImmutable('2023-12-06T13:00:00+00:00');
        $context = new RescheduleEventActionContext($eventCollection, $newDate);

        $this->calendarService->executeAction($context);