From the documentation:
namespace Album\Model;
class Album
{
public $id;
public $artist;
public $title;
public function exchangeArray($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;
}
}
Our Album entity object is a simple PHP class. In order to work with Zend\Db’s TableGateway class, we need to implement the exchangeArray() method. This method simply copies the data from the passed in array to our entity’s properties
Ok, we need to. But what's the pourpose of that function?
I mean, I've understood what that function does but I can't understand why it does things in that way.
Is it really necessary to declare all the variables?
Let's say I have a table of 20 columns and I want to select them all. Then I should declare 20 named variables.
That makes sense if I want to distinguish between public (to print) and private (internal) variables.
Is there any other reason?
It 's not just about defining class members. It 's more about object orientated benefits like encapsulation, inheritance, etc. Let 's assume your entity looks like this:
declare(strict_types=1);
namespace Application\Entity;
class Album
{
protected $id;
protected $artist;
protected $title;
public function getId() : int
{
return $this->id;
}
public function setId(int $id) : Album
{
$this->id = $id;
return $this;
}
public function getArtist() : string
{
return $this->artist;
}
public function setArtist(string $artist) : Album
{
$this->artist = $artist;
return $this;
}
public function getTitle() : string
{
return $this->title;
}
public function setTitle(string $title) : Album
{
$this->title = $title;
return $this;
}
}
First advantage using entities: there is no possibility to make typos. $data['atrist'] = 'Marcel'
will work in most cases. $album->setAtrist('Marcel')
will throw an error.
Second advantage is type hinting. Especially when you 're using PHP7 you can use the advantage of type hinting. $album->setId('1')
will throw an error because this method expects an integer value.
Third advantage is the possibility of adding some extra code to your entity. what if we need a release date and no release date is given? You can kind of validate things in entities.
protected $releaseDate;
public function getReleaseDate() : \DateTime
{
if ($this->releaseData == null) {
throw new \Exception('no release date given. evacuate!');
}
return $this->releaseDate;
}
Another advantage is hydration in zend framework. Although the exchangeArray
method is a kind of simple hydration, zend framework offers way more complex ways of hydration. What, if your release date column in the database table is of type DATE and you want your releaseDate member in your entity to be a \DateTime
object representing this date?
// data from your database
$data = [
'id' => 1,
'artist' => 'the outside agency',
'title' => 'scenocide 202',
'releaseDate' => '2010-06-30',
];
// hydration of your entity with zend 's own hydrator classes
$album = (new ClassMethods())
->addStrategy('releaseDate', new DateTimeStrategy('Y-m-d'))
->hydrate($data, new Album());
$releaseDate = $album->getReleaseDate()->format('d.m.Y');
As you can see the release date was a simple string. While hydrating your entity, the release date will be transformed to a \DateTime
object through a hydrator strategy.
These benefits are way more than distinguish between public, protected and private variables. An entity only takes and gives variables, that should be in your entity. You can use all the oo things like inheritance (implementing the \JsonSerializable
interface is pretty magic sometimes), type hinting, encapsulation, polymorphism and so on ...
Last but not least: IDE support. If your entity object is strictly php doc commented, your IDE knows what you can do with your entity. Less work for you. ;)
Edit: Table Gateway instantiation with hydrating resultset
To use the above described advantges of entity objects with hydrators in a table gateway, you have to instantiate the table gateway like in the following example.
class AlbumTableGateway extends TableGateway
{
public function __construct(Adapter $adapter)
{
$resultset = new HydratingResultset(
(new ClassMethods())->addStrategy('releaseDate', new DateTimeFormatter()),
new AlbumEntity()
);
parent::__construct('album_table', $adapter, null, $resultset);
}
public function fetchById($id)
{
$select = $this->getSql()->select();
$select->columns([
'id',
'artist',
'title',
'releaseDate',
]);
$select->where->equalTo('id', $id);
$result = $this->selectWith($select);
// get the found resultset with $result->current()->getId();
return $result;
}
}
This example assumes that the Table Gateway is created via a corresponding factory.