Rumah >pembangunan bahagian belakang >tutorial php >Mengendalikan koleksi akar agregat - corak repositori
mata teras
Melakukan persediaan awal
<code class="language-php"><?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); public function setRole($role); public function getRole(); }</code>
<code class="language-php"><?php namespace Model; class User implements UserInterface { const ADMINISTRATOR_ROLE = "Administrator"; const GUEST_ROLE = "Guest"; protected $id; protected $name; protected $email; protected $role; public function __construct($name, $email, $role = self::GUEST_ROLE) { $this->setName($name); $this->setEmail($email); $this->setRole($role); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The user ID is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = htmlspecialchars(trim($name), ENT_QUOTES); return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } public function setRole($role) { if ($role !== self::ADMINISTRATOR_ROLE && $role !== self::GUEST_ROLE) { throw new InvalidArgumentException( "The user role is invalid."); } $this->role = $role; return $this; } public function getRole() { return $this->role; } }</code>Dalam kes ini, model domain adalah lapisan rangka yang agak, hampir tidak lebih tinggi daripada pemegang data yang mudah yang dapat mengesahkan diri sendiri, yang mentakrifkan data dan tingkah laku pengguna fiktif hanya melalui antara muka terpencil dan pelaksana mudah. Untuk memastikan ia mudah dan mudah difahami, saya akan menyimpan model yang diselaraskan ini. Oleh kerana model itu sudah berjalan dalam pengasingan mudah, mari menjadikannya lebih kaya dengan menambahkan kelas lain kepadanya, yang mengendalikan pengumpulan objek pengguna. Komponen "add-on" ini hanyalah pembungkus array klasik yang mengimplementasikan antara muka SPL yang boleh dikira, dan iteratoraggregat:
<code class="language-php"><?php namespace ModelCollection; use MapperUserCollectionInterface, ModelUserInterface; class UserCollection implements UserCollectionInterface { protected $users = array(); public function add(UserInterface $user) { $this->offsetSet($user); } public function remove(UserInterface $user) { $this->offsetUnset($user); } public function get($key) { return $this->offsetGet($key); } public function exists($key) { return $this->offsetExists($key); } public function clear() { $this->users = array(); } public function toArray() { return $this->users; } public function count() { return count($this->users); } public function offsetSet($key, $value) { if (!$value instanceof UserInterface) { throw new InvalidArgumentException( "Could not add the user to the collection."); } if (!isset($key)) { $this->users[] = $value; } else { $this->users[$key] = $value; } } public function offsetUnset($key) { if ($key instanceof UserInterface) { $this->users = array_filter($this->users, function ($v) use ($key) { return $v !== $key; }); } else if (isset($this->users[$key])) { unset($this->users[$key]); } } public function offsetGet($key) { if (isset($this->users[$key])) { return $this->users[$key]; } } public function offsetExists($key) { return ($key instanceof UserInterface) ? array_search($key, $this->users) : isset($this->users[$key]); } public function getIterator() { return new ArrayIterator($this->users); } }</code>Malah, meletakkan set tatasusunan ini dalam sempadan model adalah sepenuhnya pilihan, kerana menggunakan array normal boleh menghasilkan hasil yang hampir sama. Walau bagaimanapun, dalam kes ini, dengan bergantung kepada kelas pengumpulan bebas, lebih mudah untuk mengakses set objek pengguna yang diekstrak dari pangkalan data melalui API berorientasikan objek. Selain itu, memandangkan model domain mesti sepenuhnya mengabaikan penyimpanan asas yang ditetapkan dalam infrastruktur, langkah logik seterusnya yang perlu kita ambil adalah untuk melaksanakan lapisan pemetaan yang memisahkannya dengan baik dari pangkalan data. Berikut adalah unsur -unsur yang membentuk lapisan ini:
<code class="language-php"><?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); public function setRole($role); public function getRole(); }</code>
<code class="language-php"><?php namespace Model; class User implements UserInterface { const ADMINISTRATOR_ROLE = "Administrator"; const GUEST_ROLE = "Guest"; protected $id; protected $name; protected $email; protected $role; public function __construct($name, $email, $role = self::GUEST_ROLE) { $this->setName($name); $this->setEmail($email); $this->setRole($role); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The user ID is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = htmlspecialchars(trim($name), ENT_QUOTES); return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } public function setRole($role) { if ($role !== self::ADMINISTRATOR_ROLE && $role !== self::GUEST_ROLE) { throw new InvalidArgumentException( "The user role is invalid."); } $this->role = $role; return $this; } public function getRole() { return $this->role; } }</code>
Unbox, kumpulan tugas yang dilakukan oleh Usermapper agak mudah, terhad untuk mendedahkan beberapa pencari umum yang bertanggungjawab untuk mengekstrak pengguna dari pangkalan data dan membina semula entiti yang sepadan melalui kaedah CreateUser (). Juga, jika anda telah menyelidiki beberapa pemetaan sebelum ini, dan juga menulis karya pemetaan anda sendiri, di atas pastinya mudah difahami. Satu -satunya perincian halus yang menyoroti mungkin bahawa UserCollectionInterface telah diletakkan di lapisan pemetaan, bukan dalam model. Saya melakukan ini dengan tujuan kerana dengan cara ini, abstraksi (protokol) yang koleksi pengguna bergantung secara eksplisit diisytiharkan dan dimiliki oleh usermapper peringkat yang lebih tinggi, yang konsisten dengan panduan yang dipromosikan oleh prinsip penyongsangan ketergantungan. Dengan pemetaan yang telah ditubuhkan, kami boleh menggunakannya secara langsung dari kotak dan mengeluarkan beberapa objek pengguna dari storan untuk membolehkan model menghidrat dengan segera. Walaupun ini seolah -olah menjadi jalan yang betul pada pandangan pertama, kita sebenarnya mencemarkan logik aplikasi dengan infrastruktur yang tidak perlu kerana pemetaan sebenarnya adalah sebahagian daripada infrastruktur. Bagaimana jika pada masa akan datang, perlu untuk menanyakan entiti pengguna berdasarkan keadaan yang lebih terperinci, khusus domain (bukan hanya keadaan biasa yang didedahkan oleh pencari mapper)? Dalam kes ini, ia perlu meletakkan lapisan tambahan di atas lapisan pemetaan, yang bukan sahaja menyediakan tahap akses data yang lebih tinggi, tetapi juga membawa blok logik pertanyaan melalui satu titik. Akhirnya, itulah jumlah manfaat yang kami harapkan dari pergudangan.
Melaksanakan pergudangan pengguna
Dalam persekitaran pengeluaran, pergudangan dapat melaksanakan hampir semua yang dapat difikirkan di permukaannya untuk mendedahkan ilusi set memori akar agregat kepada model. Walau bagaimanapun, dalam kes ini, kita tidak boleh mengharapkan untuk menikmati kemewahan mahal ini secara percuma, kerana gudang yang akan kita bina akan menjadi struktur yang agak buatan yang bertanggungjawab untuk mengekstrak pengguna dari pangkalan data:
<code class="language-php"><?php namespace ModelCollection; use MapperUserCollectionInterface, ModelUserInterface; class UserCollection implements UserCollectionInterface { protected $users = array(); public function add(UserInterface $user) { $this->offsetSet($user); } public function remove(UserInterface $user) { $this->offsetUnset($user); } public function get($key) { return $this->offsetGet($key); } public function exists($key) { return $this->offsetExists($key); } public function clear() { $this->users = array(); } public function toArray() { return $this->users; } public function count() { return count($this->users); } public function offsetSet($key, $value) { if (!$value instanceof UserInterface) { throw new InvalidArgumentException( "Could not add the user to the collection."); } if (!isset($key)) { $this->users[] = $value; } else { $this->users[$key] = $value; } } public function offsetUnset($key) { if ($key instanceof UserInterface) { $this->users = array_filter($this->users, function ($v) use ($key) { return $v !== $key; }); } else if (isset($this->users[$key])) { unset($this->users[$key]); } } public function offsetGet($key) { if (isset($this->users[$key])) { return $this->users[$key]; } } public function offsetExists($key) { return ($key instanceof UserInterface) ? array_search($key, $this->users) : isset($this->users[$key]); } public function getIterator() { return new ArrayIterator($this->users); } }</code>
<code class="language-php"><?php namespace Mapper; use ModelUserInterface; interface UserCollectionInterface extends Countable, ArrayAccess, IteratorAggregate { public function add(UserInterface $user); public function remove(UserInterface $user); public function get($key); public function exists($key); public function clear(); public function toArray(); }</code>
<code class="language-php"><?php namespace Mapper; use ModelRepositoryUserMapperInterface, ModelUser; class UserMapper implements UserMapperInterface { protected $entityTable = "users"; protected $collection; public function __construct(DatabaseAdapterInterface $adapter, UserCollectionInterface $collection) { $this->adapter = $adapter; $this->collection = $collection; } public function fetchById($id) { $this->adapter->select($this->entityTable, array("id" => $id)); if (!$row = $this->adapter->fetch()) { return null; } return $this->createUser($row); } public function fetchAll(array $conditions = array()) { $this->adapter->select($this->entityTable, $conditions); $rows = $this->adapter->fetchAll(); return $this->createUserCollection($rows); } protected function createUser(array $row) { $user = new User($row["name"], $row["email"], $row["role"]); $user->setId($row["id"]); return $user; } protected function createUserCollection(array $rows) { $this->collection->clear(); if ($rows) { foreach ($rows as $row) { $this->collection[] = $this->createUser($row); } } return $this->collection; } }</code>
Walaupun di atas struktur yang agak ringan, pelaksanaan userrepository sangat intuitif kerana APInya membolehkannya mengekstrak koleksi objek pengguna dari storan yang mematuhi predikat halus yang berkait rapat dengan bahasa model. Di samping itu, dalam keadaan semasa, repositori hanya mendedahkan beberapa pencari mudah kepada kod klien, yang seterusnya menggunakan fungsi pemetaan data untuk mengakses storan. Dalam persekitaran yang lebih realistik, pergudangan juga harus dapat meneruskan akar agregat. Jika anda ingin menambah kaedah sisipan () atau kaedah lain yang serupa untuk userrepository, jangan ragu untuk berbuat demikian. Dalam kedua -dua kes, cara yang berkesan untuk menangkap kelebihan sebenar menggunakan pergudangan melalui contoh adalah:
<code class="language-php"><?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); public function setRole($role); public function getRole(); }</code>
Seperti yang disebutkan sebelumnya, pergudangan secara berkesan menukar istilah perniagaan dengan kod klien (yang disebut "bahasa sejagat" yang dicipta oleh Eric Evans dalam bukunya "Reka Bentuk Domain Domain") dan bukannya istilah teknikal peringkat rendah. Tidak seperti kekaburan yang terdapat dalam Finder Mapper Data, sebaliknya, kaedah pergudangan menggambarkan dirinya dengan "nama", "e -mel", dan "peranan", yang tidak diragukan lagi sebahagian daripada sifat entiti pengguna pemodelan. Pengekstrakan data peringkat yang lebih tinggi, dan satu set lengkap yang diperlukan apabila merangkumi logik pertanyaan dalam sistem kompleks adalah salah satu sebab yang paling menarik mengapa pergudangan lebih menarik dalam reka bentuk pelbagai lapisan. Sudah tentu, kebanyakan masa, terdapat perdagangan yang tersirat di antara kerumitan untuk mendapatkan manfaat ini di hadapan dan menggunakan lapisan abstraksi tambahan (yang boleh terlalu kembung dalam aplikasi yang lebih mudah).
Kesimpulan
Sebagai salah satu konsep teras dalam reka bentuk yang didorong oleh domain, pergudangan boleh didapati dalam aplikasi yang ditulis dalam beberapa bahasa lain seperti Java dan C#, untuk menamakan beberapa. Walau bagaimanapun, dalam PHP, mereka masih tidak diketahui, hanya mengambil langkah pertama di dunia. Namun, terdapat beberapa rangka kerja yang dipercayai seperti Flow3 dan tentu saja doktrin 2.x yang dapat membantu anda mengamalkan paradigma DDD. Seperti mana -mana pendekatan pembangunan yang sedia ada, anda tidak perlu menggunakan repositori dalam permohonan anda, atau bahkan tidak perlu menghancurkannya dengan timbunan konsep di belakang DDD. Hanya gunakan akal dan pilih mereka hanya jika anda fikir ia sesuai untuk keperluan anda. Itu mudah. Gambar dari Chance Agrella / Freeheerestock.com
Soalan Lazim Mengenai Pengendalian Koleksi Root Agregat (Soalan Lazim)
Bagaimana perbezaan antara akar agregat dan entiti biasa?
Bagaimana mengenal pasti akar agregat dalam model domain saya?
Bagaimana menangani koleksi akar agregat?
Ya, akar agregat boleh merujuk kepada akar agregat yang lain, tetapi ia harus dirujuk hanya dengan pengenalan. Ini bermakna ia tidak boleh memegang rujukan langsung kepada objek akar agregat yang lain, tetapi IDnya. Ini membantu mengekalkan sempadan konsistensi untuk setiap akar agregat.
Dalam DDD, pergudangan menyediakan kaedah untuk mendapatkan dan menyimpan akar agregat. Ia menafsirkan mekanisme penyimpanan yang mendasari, yang membolehkan model domain mengabaikan butiran ketekunan data. Setiap akar agregat biasanya mempunyai storan sendiri.
Akar agregasi memainkan peranan penting dalam melaksanakan peraturan perniagaan. Ia memastikan bahawa semua perubahan kepada agregasi meletakkannya dalam keadaan yang sah. Ini bermakna mana -mana peraturan perniagaan yang merangkumi pelbagai entiti atau objek nilai hendaklah dikuatkuasakan oleh akar agregat.
Akar agregasi membantu mengurangkan kerumitan dalam model domain dengan bertindak sebagai sempadan konsistensi dan mengawal akses kepada ahli mereka. Ia memudahkan model dengan menyediakan satu titik interaksi untuk setiap pengagregatan, menjadikannya lebih mudah untuk memahami sistem.
Tidak, akar agregat tidak boleh menjadi sebahagian daripada pelbagai agregat. Ini akan melanggar sempadan konsistensi agregat dan boleh menyebabkan ketidakkonsistenan dalam model domain.
Pelbagai strategi boleh digunakan untuk menangani masalah konkurensi pada akar agregat, seperti kunci optimis atau kunci pesimis. Pilihan dasar bergantung kepada keperluan khusus permohonan dan sifat masalah keseragaman yang anda hadapi.
Output yang disemak semula ini mengekalkan pemformatan imej asal dan lokasi, memaklumkan teks untuk mengelakkan plagiarisme, dan menyimpan makna teras utuh.
Atas ialah kandungan terperinci Mengendalikan koleksi akar agregat - corak repositori. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!