We will start by going through the various ways to find and retrieve content from eZ Publish using the API. While this will be covered in further, dedicated documentation, it is necessary to explain a few basic concepts of the Public API. In the following recipes, you will learn about the general principles of the API as they are introduced in individual recipes.

Displaying values from a Content

In this recipe, we will see how to fetch a Content instance from the repository, and obtain its Field's content. 

Let's first see the full code. You can see the Command line version at https://github.com/ezsystems/CookbookBundle/blob/master/EzSystems/CookBookBundle/Command/ViewContentCommand.php.

$repository = $this->getContainer()->get( 'ezpublish.api.repository' );
$contentService = $repository->getContentService();
$fieldTypeService = $repository->getFieldTypeService();

try
{
    $content = $contentService->loadContent( 66 );
    // iterate over the field definitions of the content type and print out each field's identifier and value
    foreach( $content->contentType->fieldDefinitions as $fieldDefinition )
    {
		// ignore ezpage
        if( $fieldDefinition->fieldTypeIdentifier == 'ezpage' )
            continue;
        $output->write( $fieldDefinition->identifier . ": " );
        $fieldType = $fieldTypeService->getFieldType( $fieldDefinition->fieldTypeIdentifier );
        $field = $content->getField( $fieldDefinition->identifier );

		// We use the Field's toHash() method to get readable content out of the Field
        $valueHash = $fieldType->toHash( $field->value );
        $output->writeln( $valueHash );
    }
}
catch( \eZ\Publish\API\Repository\Exceptions\NotFoundException $e )
{
    // if the id is not found
    $output->writeln( "No content with id $contentId" );
}
catch( \eZ\Publish\API\Repository\Exceptions\UnauthorizedException $e )
{
    // not allowed to read this content
    $output->writeln( "Anonymous users are not allowed to read content with id $contentId" );
}

Let's analyze this code block by block.

$repository = $this->getContainer()->get( 'ezpublish.api.repository' );
$contentService = $repository->getContentService();
$fieldTypeService = $repository->getFieldTypeService();

This is the initialization part. As explained above, everything in the Public API goes through the repository via dedicated services. We get the repository from the service container, using the method get() of our container, obtained via $this->getContainer(). Using our $repository variable, we fetch the two services we will need using getContentService() and getFieldTypeService().

try
{
    // iterate over the field definitions of the content type and print out each field's identifier and value
    $content = $contentService->loadContent( 66 );

Everything starting from line 5 is about getting our Content, and iterating over its Fields. You can see that the whole logic is part of a try/catch block. Since the Public API uses Exceptions for error handling, this is strongly encouraged, as it will allow you to conditionally catch the various errors that may happen. We will cover the exceptions we expect in a next paragraph.

The first thing we do is use the Content Service to load a Content using its ID, 66: $contentService->loadContent( 66 ). As you can see on the API doc page, this method expects a Content ID, and returns a Content Value Object.

foreach( $content->contentType->fieldDefinitions as $fieldDefinition )
{
    // ignore ezpage
    if( $fieldDefinition->fieldTypeIdentifier == 'ezpage' )
        continue;
    $output->write( $fieldDefinition->identifier . ": " );
    $fieldType = $fieldTypeService->getFieldType( $fieldDefinition->fieldTypeIdentifier );
    $field = $content->getField( $fieldDefinition->identifier );
    $valueHash = $fieldType->toHash( $field->value );
    $output->writeln( $valueHash );
}

This block is the one that actually displays the value.

It iterates over the Content's (Content Object) fields using the ContentType's (Content Class) FieldDefinitions (Content Class Attribute) ($content->contentType->fieldDefinitions).

For each Field Definition (Content Class Attribute), we start by displaying its identifier ($fieldDefinition->identifier). We then get the FieldType (Datatype) instance using the FieldType Service ($fieldTypeService->getFieldType( $fieldDefinition->fieldTypeIdentifier )). This method expects the requested FieldType's identifier, as a string (ezstring, ezxmltext...), and returns an eZ\Publish\API\Repository\FieldType object.

The Field object (Content Object Attribute) is obtained using the getField() method of the Content Value Object we obtained using ContentService::loadContent().

Using this FieldType object, we can convert the Field's value to a hash using the toHash() method, provided by every FieldType. This method returns a native type (string, hash) out of a Field instance.

With this example, you should get a first idea of how you interact with the API. Everything is done through services, each service being responsible of a specific part of the repository (Content, FieldType...).

Since we didn't specify any language code, our Field objects is returned in the default language, depending on your languages settings in ezpublish.yml. If you want to use a non-default language, you can specify a language code in the getField() call:

$content->getField( $fieldDefinition->identifier, 'fre-FR' )
catch ( \eZ\Publish\API\Repository\Exceptions\NotFoundException $e )
{
    $output->writeln( "<error>No content with id $contentId found</error>" );
}
catch ( \eZ\Publish\API\Repository\Exceptions\UnauthorizedException $e )
{
    $output->writeln( "<error>Permission denied on content with id $contentId</error>" );
}

As said earlier, the Public API uses Exceptions to handle errors. Each method of the API may throw different exceptions, depending on what it does. Which exceptions can be thrown is usually documented for each method. In our case, loadContent() may throw two type of exceptions: NotFoundException if the requested ID wasn't found, and UnauthorizedException if the currently logged in user isn't allowed to view the requested content.

It is good practice to cover each exception you expect to happen. In this case, since our Command takes the content ID as a parameter, this ID may either not exist, or the referenced content may not be visible to our user. Both cases are covered with explicit error messages.

Browsing Locations

 

This recipe shows how to browse a subtree starting from a given location. (Full code here)

 

       try
        {
            // load the starting location and browse
            $location = $this->locationService->loadLocation( $locationId );
            $this->browseLocation( $location, 0, $output );
        }
        catch( \eZ\Publish\API\Repository\Exceptions\NotFoundException $e )
        {
            // react on location was not found
            $output->writeln( "No location with id $locationId" );
        }
        catch( \eZ\Publish\API\Repository\Exceptions\UnauthorizedException $e )
        {
            // react on permission denied
            $output->writeln( "Anonymous users are not allowed to read location with id $locationId" );
        }

 

 

 

    /**
     * this method prints out the location name and calls this method recursive for the locations children
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
     * @param int $depth the current depth
     * @param OutputInterface $output
     */
    private function browseLocation( Location $location, $depth, OutputInterface $output) {
        // indent according to depth and write out the name of the content
        for( $k=0; $k<$depth; $k++)
        {
            $output->write( ' ' );
        }
        $output->writeln( $location->contentInfo->name );
        // get location children and browse
        $children = $this->locationService->loadLocationChildren( $location );
        foreach( $children as $childLocation )
        {
            $this->browseLocation( $childLocation, $depth +1, $output );
        }
    }
eZ\Publish\API\Repository\Repository
eZ\Publish\API\Repository\LocationService

eZ\Publish\API\Repository\Values\Content\Location

eZ\Publish\API\Repository\Values\Content\ContentInfo

eZ\Publish\API\Repository\Exceptions\UnauthorizedException

eZ\Publish\API\Repository\Exceptions\NotFoundException

Viewing Content Meta Data

This recipe shows how to read content meta data: Locations, UrlAliases, Relations, Versions, Contenttype, Section, Owner, RemoteId, Several Timestamps. (Full code here)

        // get the services from the repsitory
        $contentService = $repository->getContentService();
        $locationService = $repository->getLocationService();
        $urlAliasService = $repository->getURLAliasService();
        $userService = $repository->getUserService();
        $sectionService = $repository->getSectionService();

        // load the admin user and set it has current user in the repository
        $user = $userService->loadUser( 14 );
        $repository->setCurrentUser( $user );

        try
        {
            $contentInfo = $contentService->loadContentInfo( $contentId );

            // show all locations of the content
            $locations = $locationService->loadLocations( $contentInfo );
            $output->writeln( "Locations:" );
            foreach( $locations as $location )
            {
                $output->write( "  Location: $location->pathString " ); // the path build from id's
                // printout the url alias
                $urlAlias = $urlAliasService->reverseLookup( $location );
                $output->writeln( " URLAlias: $urlAlias->path" );
            }

            // show all relations of the current version
            $versionInfo = $contentService->loadVersionInfo( $contentInfo );
            $relations = $contentService->loadRelations( $versionInfo );
            $output->writeln( "Relations:" );
            foreach( $relations as $relation )
            {
                $name = $relation->destinationContentInfo->name;
                $output->write( "  Relation of type ");
                $output->write( $this->outputRelationType( $relation->type ) );
                $output->writeln( " to content $name" );
            }

            // show meta data
            $output->writeln( "Name: $contentInfo->name" );
            $output->writeln( "Type: " .$contentInfo->contentType->identifier );
            $output->writeln( "Last modified: " . $contentInfo->modificationDate->format('Y-m-d') );
            $output->writeln( "Published: ". $contentInfo->publishedDate->format('Y-m-d') );
            $output->writeln( "RemoteId: $contentInfo->remoteId" );
            $output->writeln( "Main Language: $contentInfo->mainLanguageCode" );
            $output->writeln( "Always avaialble: " . ($contentInfo->alwaysAvailable==1?'Yes':'No' ) );
            $owner = $userService->loadUser( $contentInfo->ownerId );
            $output->writeln( "Owner: " . $owner->contentInfo->name );
            $section = $sectionService->loadSection( $contentInfo->sectionId );
            $output->writeln( "Section: $section->name" );

            // show versions
            $versionInfos = $contentService->loadVersions( $contentInfo );
            foreach ( $versionInfos as $versionInfo )
            {
                $creator = $userService->loadUser( $versionInfo->creatorId );
                $output->write( "Version $versionInfo->versionNo: '" );
                $output->write( $creator->contentInfo->name );
                $output->writeln( "' " . $this->outputStatus( $versionInfo->status ) . " " . $versionInfo->initialLanguageCode);
            }
        }
        catch( \eZ\Publish\API\Repository\Exceptions\NotFoundException $e )
        {
            // if the id is not found
            $output->writeln( "No content with id $contentId" );
        }
        catch( \eZ\Publish\API\Repository\Exceptions\UnauthorizedException $e )
        {
            // not allowed to read this content
            $output->writeln( "Anonymous users are not allowed to read content with id $contentId" );
        }

This script produces e.g the follwing output:

Locations:
  Location: /1/2/103/  URLAlias: /testrootfolder
  Location: /1/2/94/106/  URLAlias: /Partner-Section/testrootfolder
Relations:
  Relation of type EMBED to content Multivariate Testing
  Relation of type EMBED to content test
Name: testrootfolder
Type: folder
Last modified: 2012-11-12
Published: 2012-11-06
RemoteId: 32d63a1493208f6d0e2d40ab25749af4
Main Language: eng-US
Always avaialble: Yes
Owner: Administrator User
Section: Standard
Version 1: 'Administrator User' ARCHIVED eng-US
Version 2: 'Administrator User' PUBLISHED eng-US


 

Performing a simple full text search

In this recipe a simple full text search is performed. (Full code here)

        // get the repository from the di container
        $repository = $this->getContainer()->get( 'ezpublish.api.repository' );

        // get the services from repository
        $searchService = $repository->getSearchService();

        // create and execute the query and print out the result
        $query = new \eZ\Publish\API\Repository\Values\Content\Query();
        $query->criterion = new \eZ\Publish\API\Repository\Values\Content\Query\Criterion\FullText( $text );
        $result = $searchService->findContent( $query );
        $output->writeln( 'Found ' . $result->totalCount . ' items' );
        foreach( $result->searchHits as $searchHit )
        {
            $output->writeln( $searchHit->valueObject->contentInfo->name );
        }
        
eZ\Publish\API\Repository\Repository
eZ\Publish\API\Repository\SearchService

eZ\Publish\API\Repository\Values\Content\Query

eZ\Publish\API\Repository\Values\Content\Query\Criterion

eZ\Publish\API\Repository\Values\Content\Query\Criterion\Fulltext

eZ\Publish\API\Repository\Values\Content/Search/SearchResult

eZ\Publish\API\Repository\Values\Content/Search/SearchHit

eZ\Publish\API\Repository\Values\Content\ContentInfo

Performing an advanced search

In this recipe different criteria is combined using a logic 'AND' operation. The result is restricted additional (see recipe 9) to a given content type and subtree. (Full code here)

// create the query with three critions and print out the result
$query = new \eZ\Publish\API\Repository\Values\Content\Query();
$criterion1 = new Criterion\FullText( $text );
$location = $locationService->loadLocation( $locationId );
$criterion2 = new Criterion\Subtree( $location->pathString ); // restrict results to belong to the given subtree
$criterion3 = new Criterion\ContentTypeId( $contentTypeId ); // restrict to the given content type
$query->criterion = new Criterion\LogicalAND(
    array( $criterion1, $criterion2, $criterion3 )
);