আমি ভেবেছিলাম আমার নিজের প্রশ্নের উত্তর দেওয়ার জন্য আমি ক্র্যাক করব। নিম্নলিখিতটি আমার আসল প্রশ্নে সমস্যাগুলি 1-3 এর সমাধান করার একমাত্র উপায়।
দাবি অস্বীকার: নিদর্শন বা কৌশল বর্ণনা করার সময় আমি সর্বদা সঠিক শব্দ ব্যবহার করতে পারি না। তার জন্য দুঃখিত।
লক্ষ্য সমূহ:
- দেখার এবং সম্পাদনার জন্য একটি বেসিক নিয়ামকের সম্পূর্ণ উদাহরণ তৈরি করুন
Users
।
- সমস্ত কোড অবশ্যই পুরোপুরি টেস্টযোগ্য এবং মকেবল হতে হবে।
- ডেটা কোথায় সংরক্ষণ করা হয়েছে (যার অর্থ এটি পরিবর্তন করা যেতে পারে) নিয়ন্ত্রকের কোনও ধারণা থাকতে হবে না।
- একটি এসকিউএল বাস্তবায়ন দেখানোর উদাহরণ (সর্বাধিক সাধারণ)।
- সর্বাধিক পারফরম্যান্সের জন্য, নিয়ন্ত্রণকারীদের কেবল তাদের প্রয়োজনীয় ডেটা গ্রহণ করা উচিত - কোনও অতিরিক্ত ক্ষেত্র নেই।
- বিকাশের স্বাচ্ছন্দ্যের জন্য বাস্তবায়নের ক্ষেত্রে এক ধরণের ডেটা ম্যাপারকে উত্তোলন করা উচিত।
- বাস্তবায়নের জটিল ডেটা লুকআপ করার দক্ষতা থাকা উচিত।
সমাধান
আমি আমার অবিরাম স্টোরেজ (ডাটাবেস) ইন্টারঅ্যাকশনটিকে দুটি বিভাগে বিভক্ত করছি: আর (পড়ুন) এবং সিইউডি (তৈরি করুন, আপডেট করুন, মুছুন)। আমার অভিজ্ঞতা হয়েছে যে পাঠাগুলি হ'ল যা কোনও অ্যাপ্লিকেশনকে ধীর করে দেয়। এবং ডেটা ম্যানিপুলেশন (সিইউডি) আসলে ধীর হলেও এটি ঘন ঘন ঘটে এবং তাই উদ্বেগের চেয়ে অনেক কম।
সিইউডি (তৈরি করুন, আপডেট করুন, মুছুন) সহজ। এটি প্রকৃত মডেলগুলির সাথে কাজ করা জড়িত হবে , যা পরে আমার Repositories
কাছে অধ্যবসায়ের জন্য প্রেরণ করা হয় । দ্রষ্টব্য, আমার সংগ্রহস্থলগুলি এখনও একটি পঠন পদ্ধতি সরবরাহ করবে তবে কেবল অবজেক্ট তৈরির জন্য, প্রদর্শন নয়। আরও পরে।
আর (পড়ুন) এত সহজ নয়। এখানে কোনও মডেল নেই, কেবলমাত্র বস্তুর মূল্য দিন । আপনি যদি চান তবে অ্যারে ব্যবহার করুন । এই অবজেক্টগুলি একটি একক মডেল বা অনেক মডেলের সংমিশ্রণ উপস্থাপন করতে পারে, সত্যই কিছু। এগুলি তাদের নিজস্বভাবে খুব আকর্ষণীয় নয় তবে কীভাবে তারা উত্পন্ন হয় তা। আমি যা বলছি তা ব্যবহার করছি Query Objects
।
কোড:
ব্যবহারকারী মডেল
আসুন আমাদের বেসিক ব্যবহারকারী মডেলটি দিয়ে সহজ শুরু করি। নোট করুন যে কোনও ওআরএম বাড়ানোর বা ডেটাবেস স্টাফ নেই। খাঁটি মডেল গৌরব। আপনার গেটার্স, সেটারগুলি, যাচাইকরণ, যা কিছু যুক্ত করুন।
class User
{
public $id;
public $first_name;
public $last_name;
public $gender;
public $email;
public $password;
}
সংগ্রহস্থল ইন্টারফেস
আমি আমার ব্যবহারকারী সংগ্রহস্থল তৈরি করার আগে, আমি আমার সংগ্রহস্থল ইন্টারফেস তৈরি করতে চাই। এটি "চুক্তি" সংজ্ঞায়িত করবে যা আমার নিয়ামক দ্বারা ব্যবহার করার জন্য ভান্ডারগুলি অবশ্যই অনুসরণ করবে। মনে রাখবেন, আমার কন্ট্রোলার জানতে পারবে না যে ডেটা আসলে কীভাবে সংরক্ষণ করা হয়েছে।
মনে রাখবেন যে আমার সংগ্রহস্থলগুলিতে প্রতিটিতে কেবল এই তিনটি পদ্ধতি থাকবে। save()
পদ্ধতি উভয় তৈরি করে ব্যবহারকারিদের আপডেট, কেবল থাকুক বা না থাকুক ব্যবহারকারী বস্তুর একটি আইডি সেট আছে তার উপর নির্ভর করে জন্য দায়ী।
interface UserRepositoryInterface
{
public function find($id);
public function save(User $user);
public function remove(User $user);
}
এসকিউএল সংগ্রহস্থল বাস্তবায়ন
ইন্টারফেসটি এখন আমার বাস্তবায়ন তৈরি করতে। উল্লিখিত হিসাবে, আমার উদাহরণটি একটি এসকিউএল ডাটাবেসের সাথে হতে চলেছিল। পুনরাবৃত্তিশীল এসকিউএল কোয়েরিগুলি লিখতে না পারাতে ডেটা ম্যাপারের ব্যবহারটি নোট করুন ।
class SQLUserRepository implements UserRepositoryInterface
{
protected $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function find($id)
{
// Find a record with the id = $id
// from the 'users' table
// and return it as a User object
return $this->db->find($id, 'users', 'User');
}
public function save(User $user)
{
// Insert or update the $user
// in the 'users' table
$this->db->save($user, 'users');
}
public function remove(User $user)
{
// Remove the $user
// from the 'users' table
$this->db->remove($user, 'users');
}
}
প্রশ্ন অবজেক্ট ইন্টারফেস
এখন আমাদের সংগ্রহশালা দ্বারা যত্ন নেওয়া CUD (তৈরি করুন, আপডেট করুন, মুছুন), আমরা আর (পড়ুন) এ ফোকাস করতে পারি । ক্যোয়ারী অবজেক্টস হ'ল কিছু ধরণের ডেটা লুকিং লজিকের একটি এনপ্যাপুলেশন। তারা নির্মাতাদের জিজ্ঞাসা করা হয় না । এটি আমাদের সংগ্রহস্থলের মতো বিমূর্ত করে আমরা এর বাস্তবায়নটি পরিবর্তন করতে এবং এটি আরও সহজ পরীক্ষা করতে পারি। ক্যোয়ারী অবজেক্টের উদাহরণ একটি AllUsersQuery
বা AllActiveUsersQuery
, বা এমনকি হতে পারে MostCommonUserFirstNames
।
আপনি ভাবতে পারেন "আমি কি আমার অনুসন্ধানাগুলিগুলিতে কেবল এই অনুসন্ধানগুলির জন্য পদ্ধতি তৈরি করতে পারি না?" হ্যাঁ, তবে এখানে কেন আমি এটি করছি না:
- আমার সংগ্রহস্থলগুলি মডেল অবজেক্টগুলির সাথে কাজ করার জন্য। একটি আসল ওয়ার্ল্ড অ্যাপ্লিকেশনটিতে, আমি
password
যদি আমার সমস্ত ব্যবহারকারীদের তালিকা করতে চাই তবে আমাকে কেন ক্ষেত্রটি পাওয়ার দরকার হবে?
- সংগ্রহশালা প্রায়শই মডেল নির্দিষ্ট, তবুও প্রায়শই একাধিক মডেল জড়িত। তাহলে আপনি আপনার পদ্ধতিটি কী ভাণ্ডারে রেখেছেন?
- এটি আমার সংগ্রহশালাগুলিকে খুব সহজ রাখে — পদ্ধতিগুলির একটি বর্ধিত শ্রেণি নয়।
- সমস্ত প্রশ্নগুলি এখন তাদের নিজস্ব শ্রেণিতে সংগঠিত organized
- সত্যই, এই মুহুর্তে, কেবলমাত্র আমার ডাটাবেস স্তরটি বিমূর্ত করার জন্য সংগ্রহস্থলগুলি উপস্থিত রয়েছে।
আমার উদাহরণের জন্য আমি "AllUser" অনুসন্ধান করার জন্য একটি কোয়েরি অবজেক্ট তৈরি করব। ইন্টারফেসটি এখানে:
interface AllUsersQueryInterface
{
public function fetch($fields);
}
প্রশ্নের অবজেক্ট বাস্তবায়ন
এই যেখানে আমরা আবার ডেটা ম্যাপার ব্যবহার করে বিকাশের গতি বাড়িয়ে তুলতে পারি। লক্ষ্য করুন যে আমি ফিরিয়ে নেওয়া ডেটাসেট — ক্ষেত্রগুলিতে একটি টুইট করতে দিচ্ছি। এটি প্রায় যতদূর আমি সম্পাদিত ক্যোয়ারী পরিচালনা করতে চাই। মনে রাখবেন, আমার ক্যোয়ারী অবজেক্টগুলি কোয়েরি বিল্ডার নয়। তারা কেবল একটি নির্দিষ্ট ক্যোয়ারি সম্পাদন করে। তবে, যেহেতু আমি জানি যে আমি সম্ভবত এটির একটি খুব ব্যবহার করব, বিভিন্ন পরিস্থিতিতে বিভিন্ন ক্ষেত্রে আমি নিজেকে ক্ষেত্র নির্দিষ্ট করার ক্ষমতা দিচ্ছি giving আমি কখনই আমার প্রয়োজনের ক্ষেত্রগুলি ফিরতে চাই না!
class AllUsersQuery implements AllUsersQueryInterface
{
protected $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function fetch($fields)
{
return $this->db->select($fields)->from('users')->orderBy('last_name, first_name')->rows();
}
}
কন্ট্রোলারে যাওয়ার আগে, আমি এটি আরও শক্তিশালী উদাহরণের জন্য আরেকটি উদাহরণ দেখাতে চাই। হয়তো আমি একটি প্রতিবেদন ইঞ্জিন আছে এবং জন্য একটি প্রতিবেদন তৈরি করতে হবে AllOverdueAccounts
। এটি আমার ডেটা ম্যাপারটির সাথে জটিল হতে পারে এবং আমি SQL
এই পরিস্থিতিতে কিছু সত্য লিখতে চাই । কোনও সমস্যা নেই, এখানে এই ক্যোয়ারী অবজেক্টটি দেখতে কেমন:
class AllOverdueAccountsQuery implements AllOverdueAccountsQueryInterface
{
protected $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function fetch()
{
return $this->db->query($this->sql())->rows();
}
public function sql()
{
return "SELECT...";
}
}
এটি এই প্রতিবেদনের জন্য আমার যুক্তিবাদকে সুন্দরভাবে এক শ্রেণিতে রাখে এবং এটি পরীক্ষা করা সহজ। আমি এটি আমার হৃদয়ের সামগ্রীতে উপহাস করতে পারি, বা এমনকি সম্পূর্ণরূপে একটি ভিন্ন বাস্তবায়ন ব্যবহার করতে পারি।
নিয়ামক
এখন মজাদার অংশ all সমস্ত টুকরো একসাথে আনছে। নোট করুন যে আমি নির্ভরতা ইনজেকশন ব্যবহার করছি। সাধারণত নির্ভরতাগুলি কনস্ট্রাক্টরের মধ্যে ইনজেকশন দেওয়া হয়, তবে আমি আসলে এগুলি আমার নিয়ামক পদ্ধতিতে (রুটগুলি) ইনজেকশন করতে পছন্দ করি। এটি নিয়ন্ত্রণকারীর অবজেক্ট গ্রাফকে ন্যূনতম করে এবং আসলে আমি এটি আরও সুস্পষ্ট বলে মনে করি। দ্রষ্টব্য, আপনি যদি এই পদ্ধতির পছন্দ না করেন তবে কেবল theতিহ্যবাহী কনস্ট্রাক্টর পদ্ধতিটি ব্যবহার করুন।
class UsersController
{
public function index(AllUsersQueryInterface $query)
{
// Fetch user data
$users = $query->fetch(['first_name', 'last_name', 'email']);
// Return view
return Response::view('all_users.php', ['users' => $users]);
}
public function add()
{
return Response::view('add_user.php');
}
public function insert(UserRepositoryInterface $repository)
{
// Create new user model
$user = new User;
$user->first_name = $_POST['first_name'];
$user->last_name = $_POST['last_name'];
$user->gender = $_POST['gender'];
$user->email = $_POST['email'];
// Save the new user
$repository->save($user);
// Return the id
return Response::json(['id' => $user->id]);
}
public function view(SpecificUserQueryInterface $query, $id)
{
// Load user data
if (!$user = $query->fetch($id, ['first_name', 'last_name', 'gender', 'email'])) {
return Response::notFound();
}
// Return view
return Response::view('view_user.php', ['user' => $user]);
}
public function edit(SpecificUserQueryInterface $query, $id)
{
// Load user data
if (!$user = $query->fetch($id, ['first_name', 'last_name', 'gender', 'email'])) {
return Response::notFound();
}
// Return view
return Response::view('edit_user.php', ['user' => $user]);
}
public function update(UserRepositoryInterface $repository)
{
// Load user model
if (!$user = $repository->find($id)) {
return Response::notFound();
}
// Update the user
$user->first_name = $_POST['first_name'];
$user->last_name = $_POST['last_name'];
$user->gender = $_POST['gender'];
$user->email = $_POST['email'];
// Save the user
$repository->save($user);
// Return success
return true;
}
public function delete(UserRepositoryInterface $repository)
{
// Load user model
if (!$user = $repository->find($id)) {
return Response::notFound();
}
// Delete the user
$repository->delete($user);
// Return success
return true;
}
}
সর্বশেষ ভাবনা:
এখানে গুরুত্বপূর্ণ যে বিষয়গুলি লক্ষণীয় তা হ'ল আমি যখন সত্তাগুলি সংশোধন করছি (তৈরি করব, আপডেট করব বা মুছবেন) তখন আমি আসল মডেল অবজেক্টের সাথে কাজ করছি এবং আমার সংগ্রহস্থলের মাধ্যমে অধ্যবসায় সম্পাদন করছি।
যাইহোক, আমি যখন প্রদর্শন করছি (ডেটা নির্বাচন করে এটি ভিউগুলিতে প্রেরণ করছি) আমি মডেল অবজেক্টের সাথে কাজ করছি না, বরং পুরানো মানের বস্তুগুলির সাথে কাজ করছি। আমি কেবলমাত্র আমার প্রয়োজনীয় ক্ষেত্রগুলি নির্বাচন করি এবং এটি নকশাকৃত করা হয়েছে যাতে আমি আমার ডেটা সন্ধানের সর্বাধিক সম্পাদন করতে পারি।
আমার সংগ্রহশালাগুলি খুব পরিষ্কার থাকে এবং পরিবর্তে এই "জগাখিচুড়ি" আমার মডেল ক্যোয়ারীগুলিতে সাজানো হয়।
আমি বিকাশে সাহায্যের জন্য ডেটা ম্যাপার ব্যবহার করি, কারণ সাধারণ কাজগুলির জন্য পুনরাবৃত্তিশীল এসকিউএল লেখা কেবল হাস্যকর। তবে যেখানে প্রয়োজন সেখানে আপনি একেবারে এসকিউএল লিখতে পারেন (জটিল প্রশ্ন, রিপোর্টিং ইত্যাদি)। এবং আপনি যখন করেন, এটি একটি সুন্দরভাবে নামযুক্ত ক্লাসে ছড়িয়ে যায়।
আমি আমার পদ্ধতির আপনার গ্রহণ শুনে ভাল লাগবে!
জুলাই 2015 আপডেট:
আমি এই সব দিয়ে শেষ যেখানে মন্তব্য জিজ্ঞাসা করা হয়েছে। ঠিক আছে, আসলে এটি খুব দূরে নয়। সত্য সত্য, আমি এখনও সত্যিই সংগ্রহস্থল পছন্দ করি না। আমি এগুলিকে বেসিক লুপআপের জন্য ওভারকিল খুঁজে পাই (বিশেষত যদি আপনি ইতিমধ্যে একটি ORM ব্যবহার করছেন), এবং আরও জটিল প্রশ্নগুলির সাথে কাজ করার সময় অগোছালো।
আমি সাধারণত অ্যাক্টিভেকর্ড স্টাইল ওআরএম নিয়ে কাজ করি, তাই প্রায়শই আমি কেবল আমার অ্যাপ্লিকেশন জুড়ে সরাসরি সেই মডেলগুলি উল্লেখ করি। তবে, আমার আরও জটিল প্রশ্ন রয়েছে এমন পরিস্থিতিতে আমি এগুলি আরও পুনরায় ব্যবহারযোগ্য করে তুলতে ক্যোয়ারী অবজেক্টগুলি ব্যবহার করব। আমার এও লক্ষ্য করা উচিত যে আমি সর্বদা আমার পদ্ধতিগুলিতে আমার মডেলগুলি ইনজেক্ট করি, যাতে আমার পরীক্ষাগুলিতে তাদের উপহাস করা সহজ হয় making