Mugo Web main content.

An introduction to fetching content in eZ Publish 4 and eZ Publish 5

By: Ernesto Buenrostro | April 28, 2014 | eZ Publish development tips

Fetching content the new way on eZ Publish 5.x.

In the following article we are going to show you how to fetch information in the new eZ Publish version considering that permissions may be set in place on different sections and we will compare it to how is it done in the legacy kernel.

During the flow of this article we will introduce a new undocumented method which is going to let us bypass permissions set to different sections.

In our example, let's suppose that we are displaying a set of images in the media library. These images are displayed within the content structure tree, but aren't supposed to be directly accessible in the media library. Therefore, the anonymous user does not have permission to directly view those images and we need to bypass that permission limitation in our fetches.

Fetching content in eZ Publish legacy

Using the current user

This simple fetch will return a list of the images that we have, although if the anonymous user does not have permissions for that folder in the media library, we will get an empty result.

(In our eZ Publish legacy code examples, we are showing example template code. For eZ Publish 5, we are showing PHP code in a custom controller, since data fetches are now expected to be done in PHP land. Please see the official eZ Publish documentation for more information.)

{def
    $image_parent_node_id = 63
    $images = fetch( "content", "list", hash(
        "parent_node_id"       => $image_parent_node_id
        , "class_filter_type"  => "include"
        , "class_filter_array" => array( "image" )
    ) )
}

{* Do something with the results *}
...

Overriding permissions

We can override the permissions for our fetch by passing an empty array as the "limitation" parameter in our fetch:

{def
    $image_parent_node_id = 63
    $images = fetch( "content", "list", hash(
        "parent_node_id"       => $image_parent_node_id
        , "class_filter_type"  => "include"
        , "class_filter_array" => array( "image" )
        , "limitation"         => array()
    ) )
}

{* Do something with the results *}
...

For more information on the fetch function parameters, see the eZ Publish 4.x documentation.

Fetching content in eZ Publish 5.x

eZ Publish 5.x fetches are based on a new API that introduces a new query handler and "Criterion" objects.

Using the current user

The example below is similar in its parameters to the legacy example, except that you have to explicitly specify that you want to fetch visible (and not hidden) content. However, if the current user does not have the necessary permissions to read content in the media library folder, we will get an exception of the type \eZ\Publish\API\Repository\Exceptions\NotFoundException.

public function getImagesAction()
{
    $repository = $this->getRepository();

    $imageParentNodeID = 63;

    // here we are going to use the Query and Criterion objects to do our fetch
    $query = new Query();
    $query->criterion = new Criterion\LogicalAnd(array(
        new Criterion\Subtree($repository->getLocationService()->loadLocation( $imageParentNodeID )->pathString ),
        new Criterion\ContentTypeIdentifier( 'image' ),
        new Criterion\Visibility( Criterion\Visibility::VISIBLE ),
    ) );

    /* To execute our query we are going to pass it as a argument to the method
     * SearchService::findContent()
     */
    $searchHits = $repository->getSearchService()->findContent( $query )->searchHits;

    // Then we have to build the array to be passed to our view
    $contentArray = new array();
    foreach( $searchHits as $searchHit )
    {
        $content = $searchHit->valueObject;
        $contentArray[] = $content;
    }

    return $this->render(
        'MugoTestBundle:Parts:image_list.html.twig'
        , array(
            'content' => $contentArray
        )
    );
}

Using an admin user

We can use a user with the necessary permissions in order to do the fetch. We can do this with the user service and either the username or user ID:

loadUserByLogin( $userName )

or

loadUser( $userId )

public function getImagesAction()
{
    $repository = $this->getRepository();

    // Setting the repository user
    $repository->setCurrentUser( $repository->getUserService()->loadUserByLogin( 'admin' ) );

    $imageParentNodeID = 63;

    $query = new Query();
    $query->criterion = new Criterion\LogicalAnd( array(
        new Criterion\Subtree($repository->getLocationService()->loadLocation( $imageParentNodeID )->pathString ),
        new Criterion\ContentTypeIdentifier( 'image' ),
        new Criterion\Visibility( Criterion\Visibility::VISIBLE ),
    ) );

    $searchHits = $repository->getSearchService()->findContent( $query )->searchHits;
    $contentArray = new array();
    foreach( $searchHits as $searchHit )
    {
        $content = $searchHit->valueObject;
        $contentArray[] = $content;
    }

    return $this->render(
        'MugoTestBundle:Parts:image_list.html.twig'
        , array(
            'content' => $contentArray
        )
    );
}

Using the sudo method

Wait what is sudo? No, you don't have to use the command line. sudo is an undocumented (so far) eZ Publish function to bypass permission limitations without having to switch to a specific user.

The way to use the sudo method is with a PHP closure; you fetch the content within the closure:

public function getImagesAction()
{
    $repository = $this->getRepository();
    $imagesNodeId = 63;

    $restrictedContent = $repository->sudo(
        function( $repository ) use( $imagesNodeId ) {
            $query = new Query();
            $query->criterion = new Criterion\LogicalAnd( array(
                new Criterion\Subtree( $repository->getLocationService()->loadLocation( $imagesNodeId )->pathString ),
                new Criterion\ContentTypeIdentifier( 'image' ),
                new Criterion\Visibility( Criterion\Visibility::VISIBLE ),
            ));

            $searchHits = $repository->getSearchService()->findContent( $query )->searchHits;

            // We will create an array with all the content objects
            $contentArray = new array();
            foreach( $searchHits as $searchHit )
            {
                $content = $searchHit->valueObject;
                $contentArray[] = $content;
            }

            return $contentArray;
        }
    );
    return $this->render(
        'MugoTestBundle:Parts:image_list.html.twig'
        , array(
            'content' => $restrictedContent
        )
    );
}

Extra note: exceptions in eZ Publish 5.x

In the eZ Publish legacy kernel, you get a result of null or false if you tried to fetch an object or node/location that didn't exist. Or if you didn't have the necessary permissions, you just get an empty result. eZ Publish 5 relies heavily on exceptions in such cases, and you must catch those exceptions.

Expanding on our last example above, below we fetch a specific content object based on its ID with the sudo function and with proper exception handling.

public function getImageAction()
{
    $repository = $this->getRepository();

    // Restricted image located in the media library
    $contentId = 66;
    
    $restrictedContent = $repository->sudo(
        function( $repository ) use( $contentId )
        {
            try
            {
                $contentInfo = $repository->getContentService()->loadContent( $contentId );
            }
            catch( \eZ\Publish\API\Repository\Exceptions\UnauthorizedException $e )
            {
                // this exception would occur if we weren't using sudo or an authorized user
                return false;
            }
            catch( \eZ\Publish\API\Repository\Exceptions\NotFoundException $e )
            {
                // this exception would occur if the content we are looking does not exist
                return false;
            }
            return $content;
        }
    );

    return $this->render(
        'MugoTestBundle:Parts:image.html.twig'
        , array(
            'content' => $restrictedContent
        )
    );
}

Fetching content in eZ Publish 5 has many similarities to fetching content in eZ Publish 4. If you give proper attention to handling permissions and catching exceptions, you can ensure that you get the content results you need!