Php 如何在sql查询中使用数据映射器
我很难理解datamapper设计模式。我有两个问题(一个是获取相册,另一个是获取艺术家)。我想制作一张专辑和艺术家(乐队成员)的名单。两者之间存在一对多的关系 SQL查询Php 如何在sql查询中使用数据映射器,php,mysql,zend-framework,zend-framework2,datamapper,Php,Mysql,Zend Framework,Zend Framework2,Datamapper,我很难理解datamapper设计模式。我有两个问题(一个是获取相册,另一个是获取艺术家)。我想制作一张专辑和艺术家(乐队成员)的名单。两者之间存在一对多的关系 SQL查询 public function getArtist() { $adapter = $this->getAdapter(); $sql = new Sql($adapter); $select = $sql->select(); $select->from('genre');
public function getArtist()
{
$adapter = $this->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('genre');
$select->where(array(
'album_id' => $album,));
$selectString = $sql->getSqlStringForSqlObject($select);
$resultSet = $adapter->query($selectString, $adapter::QUERY_MODE_EXECUTE);
return $resultSet;
}
public function getAlbum()
{
$adapter = $this->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('album');
$selectString = $sql->getSqlStringForSqlObject($select);
$resultSet = $adapter->query($selectString, $adapter::QUERY_MODE_EXECUTE);
return $resultSet;
}
当我执行类似于下面的操作时,我最终会对每个相册运行一个单独的查询。我不想这样做。我该怎么设置这样的东西呢?我是否可以设置为每个实体表示一个查询(我希望在查询中使用联接,而不是为每个表创建实体)
ConcreteMemberMapper.php
use Zend\Db\Adapter\AdapterInterface;
use Album\Model\AlbumMapper;
namespace Album\Model;
class ConcreteAlbumMapper implements AlbumMapper {
public function __construct(AdapterInterface $dbAdapter)
{
$this->adapter =$dbAdapter;
}
public function fetchAlbums(ArtistMapper $artistMapper) {
$adapter = $this->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('album');
$selectString = $sql->getSqlStringForSqlObject($select);
$albumRows = $adapter->query($selectString, $adapter::QUERY_MODE_EXECUTE);
$albums = array();
foreach ($albumRows as $albumRow) {
$albums[$albumRow['id']] = new Album($albumRow);
}
$artists = $artistMapper->fetchByAlbumIds(array_keys($albums));
//marrying album and artists
foreach ($artists as $artist) {
/**
* not crazy about the getAlbumId() part, would be better to say
* $artist->attachYourselfToAnAlbumFromThisIndexedCollection($albums);
* but going with this for simplicity
*/
$albums[$artist->getAlbumId()]->addArtist($artist);
}
return $albums;
}
}
<?php
namespace Album\Model;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\Sql\Sql;
use Album\Model\Member;
class ConcreteMemberMapper {
public function __construct(AdapterInterface $dbAdapter)
{
$this->adapter =$dbAdapter;
}
public function getAdapter()
{
if (!$this->adapter) {
$sm = $this->getServiceLocator();
$this->adapter = $sm->get('Zend\Db\Adapter\Adapter');
}
return $this->adapter;
}
public function fetchByAlbumIds($ids) {
$adapter = $this->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('members');
$select->where(array(
'album_id' => $ids));
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $adapter->query($selectString, $adapter::QUERY_MODE_EXECUTE);
return $results;
//return \Zend\Stdlib\ArrayUtils::iteratorToArray($results);
}
public function getAlbumId()
{
return $this->albumId;
}
}
<?php
namespace Album\Model;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class Album //implements InputFilterAwareInterface
{
public $id;
public $title;
public $artist;
public $members = array();
public function __construct($data) {
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->artist = (!empty($data['artist'])) ? $data['artist'] : null;
$this->title = (!empty($data['title'])) ? $data['title'] : null;
$this->members = (!empty($data['members'])) ? $data['members'] : null;
}
public function addMember(Member $member) {
$this->members[] = $member;
}
public function indexAction()
{
$dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
//$album = new Album();
$albumMapper = new ConcreteAlbumMapper($dbAdapter);
$memberMapper = new ConcreteMemberMapper($dbAdapter);
$bar=$albumMapper->fetchAlbums($memberMapper);
//$artistMapper = new
//var_dump($bar);
return new ViewModel(array(
'albums' => $bar,
));
}
非常感谢马特有很多方法可以做到这一点,这就是其中之一。假设您有一个类似于以下内容的db模式: 现在,您可以让AlbumMapper和ArtistMapper负责为您从数据库中获取这些对象:
interface AlbumMapper {
/**
* Fetches the albums from the db based on criteria
* @param type $albumCriteria
* @param ArtistMapper $artistMapper
*
* Note: the ArtistMapper here can be also made optional depends on your app
*/
public function fetchBySomeCriteria($albumCriteria, ArtistMapper $artistMapper);
}
interface ArtistMapper {
/**
* @param array $ids
* @return Artist[]
*/
public function fetchByAlbumIds(array $ids);
}
我已经指出,AlbumMapper需要ArtistMapper,因此使用此mapper,相册总是与艺术家一起返回。现在,一个示例实现可以是这样的,我使用一个小索引技巧将艺术家附加到相册:
class ConcreteAlbumMapper implements AlbumMapper {
public function fetchBySomeCriteria($albumCriteria, ArtistMapper $artistMapper) {
//sql for fetching rows from album table based on album criteria
$albums = array();
foreach ($albumRows as $albumRow) {
$albums[$albumRow['id']] = new Album($albumRow);
}
$artists = $artistMapper->fetchByAlbumIds(array_keys($albums));
//marrying album and artists
foreach ($artists as $artist) {
/**
* not crazy about the getAlbumId() part, would be better to say
* $artist->attachYourselfToAnAlbumFromThisIndexedCollection($albums);
* but going with this for simplicity
*/
$albums[$artist->getAlbumId()]->addArtist($artist);
}
return $albums;
}
}
在这种情况下,您的相册将遵循以下内容:
class Album {
private $id;
private $title;
private $artists = array();
public function __construct($data) {
//initialize fields
}
public function addArtist(Artist $artist) {
$this->artists[] = $artist;
}
}
在所有这些结束时,您应该有一个由艺术家初始化的相册对象集合。您必须从根本上更改代码,并执行
join
查询,以便在一次查询中获取相册+艺术家信息。相册上的我的foreach不会重复吗?我希望每张专辑都能回音一次,如果有艺术家在专辑下面回音的话。这就是为什么我有多个要求(我不想重复信息)。每个相册有多个艺术家(乐队成员)。SQL是否进入相册映射器界面?还是映射器?我的控制器会改变吗?我现在会创建一个新的Album实例而不是searchQuery吗$相册=新相册()//$艺术家=新的搜索查询($dbAdapter);不知道你的控制器里有什么。这里的想法是使用WHERE album_id IN($AlbumID)根据专辑id获取艺术家。这样,您将有2个db查询,而不是像结果中有相册那样多的查询。您对相册的db查询将进入ConcreteAlbumMapper,类似地,关于艺术家的db查询将存在于ConcreteArtistMapper(一些ArtistMapper实现)中。明白了。我会继续修补的。我在掌握实现这个逻辑所需的代码方面有点困难,如果你有任何你推荐我读过的源代码(我已经到处搜索了,但找不到具体的例子),我对上面的设置有两个问题。在ConcreateArtistMapper上,我得到一个错误(文本编辑器告诉我它不是抽象的)。控制器也不正确(传递的参数不正确)
class Album {
private $id;
private $title;
private $artists = array();
public function __construct($data) {
//initialize fields
}
public function addArtist(Artist $artist) {
$this->artists[] = $artist;
}
}