Как лениво загружать дочерние объекты с шаблоном Data Mapper? - PullRequest
3 голосов
/ 28 сентября 2011

Если у меня достаточно сложная модель User, для которой я хотел бы использовать шаблон отображения данных для загрузки, как бы я лениво загружал некоторые более интенсивные биты пользовательской информации, не позволяя пользователю знать о UserMapper?

Например - если модель User допускает массив объектов Address (и у пользователя может быть много из них, но не обязательно, если они нужны), как я могу загрузить этот объект, если / когда это потребуется?

Сделать ли модель User осведомленной о AddressMapper?

Передать ли модель BACK пользователя в UserMapper, который затем гидратирует только адреса?

Есть ли лучший вариант?

1 Ответ

7 голосов
/ 28 сентября 2011

Ну, я однажды нашел следующий умный шаблон, любезно предоставленный Беном Шольценом , разработчиком для Zend Framework. Это выглядит примерно так:

class ModelRelation
    implements IteratorAggregate
{
    protected $_iterator;
    protected $_mapper;
    protected $_method;
    protected $_arguments;

    public function __construct( MapperAbstract $mapper, $method, array $arguments = array() )
    {
        $this->_mapper    = $mapper;
        $this->_method    = $method;
        $this->_arguments = $arguments;
    }

    public function getIterator()
    {
        if( $this->_iterator === null )
        {
            $this->_iterator = call_user_func_array( array( $this->_mapper, $this->_method ), $this->_arguments );
        }

        return $this->_iterator;
    }

    public function __call( $name, array $arguments )
    {        
        return call_user_func_array( array( $this->getIterator(), $name ), $arguments );
    }
}

Реальная реализация Бена Шольцена здесь .

То, как вы бы это использовали, выглядит примерно так:

class UserMapper
    extends MapperAbstract
{
    protected $_addressMapper;

    public function __construct( AddressMapper $addressMapper )
    {
        $this->_addressMapper = $addressMapper;
    }

    public function getUserById( $id )
    {
        $userData = $this->getUserDataSomehow();

        $user = new User( $userData );
        $user->addresses = new ModelRelation(
            $this->_addressesMapper,
            'getAddressesByUserId',
            array( $id )
        );

        return $user;
    }
}

class AddressMapper
    extends MapperAbstract
{
    public function getAddressesByUserId( $id )
    {
        $addressData = $this->getAddressDataSomehow();

        $addresses = new SomeAddressIterator( $addressData );

        return $addresses;
    }
}

$user = $userMapper->getUserById( 3 );
foreach( $user->addresses as $address ) // calls getIterator() of ModelRelation
{
    // whatever
}

Дело в том, хотя; это может стать очень медленным, если графы объектов становятся очень сложными и глубоко вложенными в какой-то момент, потому что все преобразователи должны запрашивать свои собственные данные (предполагая, что вы используете базу данных для сохранения). Я испытал это, когда использовал этот шаблон для CMS, чтобы получить вложенные Pages объекты (произвольно глубокие дочерние страницы).

Вероятно, его можно настроить с помощью некоторого механизма кэширования, чтобы значительно ускорить процесс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...