অস্বীকৃতি: পিএইচপি-ভিত্তিক ওয়েব অ্যাপ্লিকেশনগুলির প্রসঙ্গে আমি এমভিসি-জাতীয় প্যাটার্নগুলি কীভাবে বুঝি তার একটি বিবরণ নীচে দেওয়া হয়েছে। সামগ্রীতে ব্যবহৃত সমস্ত বাহ্যিক লিঙ্কগুলি শর্তাদি এবং ধারণাগুলি ব্যাখ্যা করার জন্য রয়েছে এবং বিষয়টিতে আমার নিজের বিশ্বাসযোগ্যতা বোঝাতে নয় ।
যে জিনিসটি আমি পরিষ্কার করতে হবে তা হ'ল: মডেলটি একটি স্তর ।
দ্বিতীয়: শাস্ত্রীয় এমভিসি এবং আমরা ওয়েব বিকাশে যা ব্যবহার করি তার মধ্যে পার্থক্য রয়েছে । আমি লিখেছিলাম এমন কিছু পুরানো উত্তর এখানে দেওয়া হয়েছে , যা সেগুলি কীভাবে আলাদা তা সংক্ষেপে বর্ণনা করে।
একটি মডেল কি নয়:
মডেলটি কোনও শ্রেণি বা কোনও একক বস্তু নয়। এটি করা খুব সাধারণ একটি ভুল (আমিও করেছি, যদিও আমি অন্যথায় শিখতে শুরু করার সময় মূল উত্তরটি লেখা হয়েছিল) , কারণ বেশিরভাগ ফ্রেমওয়ার্কগুলি এই ভুল ধারণাটি স্থায়ী করে দেয়।
এটি কোনও অবজেক্ট-রিলেশনাল ম্যাপিং টেকনিক (ওআরএম) বা ডাটাবেস টেবিলগুলির বিমূর্ততা নয়। যে কেউ আপনাকে অন্যথায় বলে সে সম্ভবত অন্য একটি ব্র্যান্ড-নতুন ওআরএম বা একটি পুরো কাঠামো 'বিক্রয়' করার চেষ্টা করছে ।
একটি মডেল কি:
সঠিক MVC অভিযোজন মধ্যে, এম সব ডোমেন ব্যবসা লজিক রয়েছে এবং মডেল লেয়ার হয় বেশিরভাগ স্ট্রাকচার তিন ধরনের থেকে তৈরি:
ডোমেন অবজেক্টস
একটি ডোমেন অবজেক্ট হ'ল যুক্তিযুক্ত ডোমেন তথ্যের একটি যৌক্তিক ধারক; এটি সাধারণত সমস্যা ডোমেন স্পেসে একটি যৌক্তিক সত্তাকে উপস্থাপন করে। সাধারণত ব্যবসায়িক যুক্তি হিসাবে পরিচিত ।
আপনি চালান প্রেরণের আগে কীভাবে ডেটা বৈধ করতে হবে বা কোনও অর্ডারের মোট ব্যয় গণনা করতে হবে তা এখানেই নির্ধারণ করা হবে। একই সময়ে, ডোমেন অবজেক্টস তন্ন তন্ন থেকে - সঞ্চয়ের সম্পূর্ণরূপে অবিদিত যেখানে (SQL ডাটাবেস, বাকি এপিআই, টেক্সট ফাইল, ইত্যাদি) এমনকি যদি তারা সংরক্ষিত হবে না বা উদ্ধার করা হয়।
ডেটা ম্যাপার্স
এই অবজেক্টগুলি কেবল স্টোরেজের জন্য দায়ী। আপনি যদি কোনও ডাটাবেসে তথ্য সঞ্চয় করেন তবে এসকিউএল যেখানে থাকে সেখানে এটি থাকবে। অথবা হতে পারে আপনি ডেটা সঞ্চয় করার জন্য একটি এক্সএমএল ফাইল ব্যবহার করেন এবং আপনার ডেটা ম্যাপারগুলি এক্সএমএল ফাইলগুলি এবং এর থেকে পার্স করছে।
সেবা
আপনি এগুলিকে "উচ্চ স্তরের ডোমেন অবজেক্টস" হিসাবে ভাবতে পারেন তবে ব্যবসায়িক যুক্তির পরিবর্তে পরিষেবাগুলি ডোমেন অবজেক্টস এবং ম্যাপারদের মধ্যে মিথস্ক্রিয়তার জন্য দায়বদ্ধ । এই কাঠামোগুলি ডোমেন ব্যবসায় যুক্তির সাথে ইন্টারঅ্যাক্ট করার জন্য "সর্বজনীন" ইন্টারফেস তৈরি করে। আপনি এগুলি এড়াতে পারেন তবে কন্ট্রোলারগুলিতে কিছু ডোমেন যুক্তি ফাঁস করার দণ্ডে ।
এসিএল বাস্তবায়ন প্রশ্নে এই বিষয়ের সাথে সম্পর্কিত উত্তর রয়েছে - এটি কার্যকর হতে পারে।
মডেল স্তর এবং এমভিসি ত্রিয়ার অন্যান্য অংশের মধ্যে যোগাযোগ কেবল পরিষেবাগুলির মাধ্যমেই হওয়া উচিত । স্পষ্ট বিচ্ছেদটির কয়েকটি অতিরিক্ত সুবিধা রয়েছে:
- এটি একক দায়িত্বের নীতিটি প্রয়োগ করতে সহায়তা করে (এসআরপি)
- যুক্তি পরিবর্তিত হলে অতিরিক্ত 'উইগল রুম' সরবরাহ করে
- নিয়ামকটিকে যতটা সম্ভব সহজ রাখে
- আপনার যদি কোনও বাহ্যিক এপিআই দরকার হয় তবে একটি পরিষ্কার ব্লুপ্রিন্ট দেয়
কোনও মডেলের সাথে কীভাবে যোগাযোগ করবেন?
পূর্বশর্ত: ঘড়ি বক্তৃতা 'গ্লোবাল রাজ্য এবং Singletons " এবং " জিনিসের জন্য তাকান না! " ক্লিন কোড আলোচনা থেকে।
পরিষেবা দৃষ্টান্ত অ্যাক্সেস অর্জন
উভয় জন্য দেখুন এবং কন্ট্রোলার দৃষ্টান্ত (আপনি কি বলতে পেরেছিলাম: "UI 'তে স্তর") তে অ্যাক্সেস এই পরিষেবাগুলি, দুই সাধারণ পন্থা আছে হবে:
- আপনি সরাসরি নিজের ভিউ এবং কন্ট্রোলারগুলির নির্মাত্রে প্রয়োজনীয় পরিষেবাগুলি ইনজেক্ট করতে পারেন, সম্ভবত ডিআইআই ধারক ব্যবহার করে।
- আপনার সমস্ত দর্শন এবং নিয়ামকগুলির জন্য বাধ্যতামূলক নির্ভরতা হিসাবে পরিষেবার জন্য কারখানাটি ব্যবহার করা।
আপনার সন্দেহ হতে পারে যে ডিআই কনটেইনারটি অনেক বেশি মার্জিত সমাধান (যদিও কোনও নবজাতকের পক্ষে সবচেয়ে সহজ না হওয়া)। দুটি গ্রন্থাগার, যেটি আমি এই কার্যকারিতার জন্য বিবেচনা করার পরামর্শ দিচ্ছি তা হ'ল সিফমোনির স্বতন্ত্র নির্ভরতা ইনজেকশন উপাদান বা অরিন ।
একটি কারখানা এবং একটি ডিআই কনটেইনার ব্যবহার করে উভয় সমাধান আপনাকে বিভিন্ন সার্ভারের উদাহরণগুলি নির্বাচিত নিয়ামকের মধ্যে ভাগ করে দেওয়া এবং প্রদত্ত অনুরোধ-প্রতিক্রিয়া চক্রের জন্য দেখতে দেয়।
মডেল রাজ্যের পরিবর্তন
এখন আপনি নিয়ন্ত্রণকারীদের মধ্যে মডেল স্তর অ্যাক্সেস করতে পারেন, আপনার এগুলিকে আসলে ব্যবহার শুরু করা দরকার:
public function postLogin(Request $request)
{
$email = $request->get('email');
$identity = $this->identification->findIdentityByEmailAddress($email);
$this->identification->loginWithPassword(
$identity,
$request->get('password')
);
}
আপনার কন্ট্রোলারগুলির একটি খুব স্পষ্ট কাজ রয়েছে: ব্যবহারকারী ইনপুট নিন এবং এই ইনপুটটির উপর ভিত্তি করে ব্যবসায়ের যুক্তির বর্তমান অবস্থা পরিবর্তন করুন। এই উদাহরণে যে রাজ্যগুলির মধ্যে পরিবর্তন করা হয়েছে সেগুলি হ'ল "বেনামে ব্যবহারকারী" এবং "লগ ইন ব্যবহারকারী"।
ব্যবহারকারীর ইনপুট বৈধকরণের জন্য কন্ট্রোলার দায়বদ্ধ নয়, কারণ এটি ব্যবসায়ের নিয়মের একটি অংশ এবং নিয়ামক অবশ্যই এসকিউএল কোয়েরিগুলিকে কল করছেন না, যেমন আপনি এখানে বা এখানে দেখতে পাবেন (দয়া করে তাদের প্রতি ঘৃণা করবেন না, তারা বিপথগামী নয়)।
ব্যবহারকারীকে রাষ্ট্র-পরিবর্তন দেখাচ্ছে।
ঠিক আছে, ব্যবহারকারী লগ ইন করেছেন (বা ব্যর্থ হয়েছে)। এখন কি? বলেছেন ব্যবহারকারী এখনও এটি সম্পর্কে অজানা। সুতরাং আপনাকে প্রকৃতপক্ষে একটি প্রতিক্রিয়া তৈরি করতে হবে এবং এটি দেখার একটি দায়বদ্ধতা।
public function postLogin()
{
$path = '/login';
if ($this->identification->isUserLoggedIn()) {
$path = '/dashboard';
}
return new RedirectResponse($path);
}
এই ক্ষেত্রে, ভিউ মডেল স্তরের বর্তমান অবস্থার উপর ভিত্তি করে দুটি সম্ভাব্য প্রতিক্রিয়ার মধ্যে একটি তৈরি করেছে। একটি ভিন্ন ব্যবহারের ক্ষেত্রে আপনার কাছে "বর্তমান নিবন্ধের নির্বাচিত নির্বাচিত" জাতীয় কোনও কিছুর উপর ভিত্তি করে রেন্ডার করতে বিভিন্ন টেমপ্লেট বাছাই করা ভিউ থাকবে।
উপস্থাপনা স্তরটি এখানে আসলে বর্ণিত হিসাবে যথেষ্ট বিস্তৃত হতে পারে: পিএইচপি-তে এমভিসি ভিউগুলি বোঝা ।
তবে আমি কেবল একটি REST এপিআই তৈরি করছি!
অবশ্যই, এমন পরিস্থিতি রয়েছে যখন এটি ওভারকিল হয়।
এমভিসি কনসার্নস নীতি পৃথকীকরণের জন্য একটি দৃ concrete় সমাধান । এমভিসি ব্যবহারকারীর ইন্টারফেসটিকে ব্যবসায়ের যুক্তি থেকে পৃথক করে এবং এটি ইউআইতে এটি ব্যবহারকারীর ইনপুট এবং উপস্থাপনা পরিচালনা করে। এটি অত্যন্ত গুরুত্বপূর্ণ। যদিও প্রায়শই লোকেরা এটিকে "ত্রয়ী" হিসাবে বর্ণনা করে, এটি আসলে তিনটি স্বতন্ত্র অংশ থেকে তৈরি হয় না। কাঠামোটি আরও এরকম:
এর অর্থ হ'ল, যখন আপনার উপস্থাপনা স্তরের যুক্তি অস্তিত্বের কাছাকাছি থাকে, তখন ব্যবহারিক পদ্ধতির মাধ্যমে এগুলিকে একক স্তর হিসাবে রাখা হয়। এটি মডেল স্তরের কিছু দিকও যথেষ্ট সরল করতে পারে।
এই পদ্ধতির ব্যবহার করে লগইন উদাহরণ (একটি এপিআই এর জন্য) এইভাবে লেখা যেতে পারে:
public function postLogin(Request $request)
{
$email = $request->get('email');
$data = [
'status' => 'ok',
];
try {
$identity = $this->identification->findIdentityByEmailAddress($email);
$token = $this->identification->loginWithPassword(
$identity,
$request->get('password')
);
} catch (FailedIdentification $exception) {
$data = [
'status' => 'error',
'message' => 'Login failed!',
]
}
return new JsonResponse($data);
}
যদিও এটি টেকসই নয়, যখন আপনার প্রতিক্রিয়া বডির রেন্ডারিংয়ের জন্য জটিল যুক্তি রয়েছে, তখন আরও সরল পরিস্থিতিগুলির জন্য এই সরলীকরণটি খুব কার্যকর। তবে সাবধান করে দিন , জটিল উপস্থাপনা যুক্তিযুক্ত বৃহত্তর কোডবেসে ব্যবহার করার চেষ্টা করার সময় এই পদ্ধতিটি দুঃস্বপ্নে পরিণত হবে।
কিভাবে তৈরি করবেন মডেল?
যেহেতু কোনও একক "মডেল" শ্রেণি নেই (উপরে বর্ণিত হিসাবে) আপনি সত্যই "মডেলটি তৈরি করেন না"। পরিবর্তে আপনি পরিষেবা তৈরি করা শুরু করেন , যা কিছু নির্দিষ্ট পদ্ধতি সম্পাদন করতে সক্ষম। এবং তারপরে ডোমেন অবজেক্টস এবং ম্যাপারগুলি প্রয়োগ করুন ।
একটি পরিষেবা পদ্ধতির উদাহরণ:
উপরের উভয় পদ্ধতির মধ্যে সনাক্তকরণ পরিষেবার জন্য এই লগইন পদ্ধতি ছিল। আসলে দেখতে কেমন লাগবে। আমি একটি লাইব্রেরি থেকে একই কার্যকারিতার সামান্য পরিবর্তিত সংস্করণ ব্যবহার করছি , যা আমি লিখেছিলাম .. কারণ আমি অলস:
public function loginWithPassword(Identity $identity, string $password): string
{
if ($identity->matchPassword($password) === false) {
$this->logWrongPasswordNotice($identity, [
'email' => $identity->getEmailAddress(),
'key' => $password, // this is the wrong password
]);
throw new PasswordMismatch;
}
$identity->setPassword($password);
$this->updateIdentityOnUse($identity);
$cookie = $this->createCookieIdentity($identity);
$this->logger->info('login successful', [
'input' => [
'email' => $identity->getEmailAddress(),
],
'user' => [
'account' => $identity->getAccountId(),
'identity' => $identity->getId(),
],
]);
return $cookie->getToken();
}
আপনি দেখতে পাচ্ছেন, বিমূর্তির এই স্তরে, কোথা থেকে ডেটা আনা হয়েছিল তার কোনও ইঙ্গিত নেই। এটি একটি ডাটাবেস হতে পারে তবে এটি পরীক্ষার উদ্দেশ্যে কেবল একটি মক অবজেক্টও হতে পারে। এমনকি এটির জন্য ব্যবহৃত ডেটা ম্যাপারগুলিও private
এই পরিষেবাটির পদ্ধতিতে লুকিয়ে রয়েছে।
private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
$identity->setStatus($status);
$identity->setLastUsed(time());
$mapper = $this->mapperFactory->create(Mapper\Identity::class);
$mapper->store($identity);
}
ম্যাপার তৈরি করার উপায়
অধ্যবসায়ের একটি বিমূর্ততা বাস্তবায়নের জন্য, সবচেয়ে নমনীয় পন্থায় কাস্টম ডেটা ম্যাপার তৈরি করা হয় ।
থেকে: পিওএএএ বই
অনুশীলনে তারা নির্দিষ্ট ক্লাস বা সুপারক্লাসের সাথে ইন্টারঅ্যাক্ট করার জন্য প্রয়োগ করা হয়। আপনাকে Customer
এবং Admin
আপনার কোডটিতে (উভয়ই একটি User
সুপারক্লাস থেকে উত্তরাধিকারসূত্রে ) বলা যাক। উভয়ই সম্ভবত একটি পৃথক ম্যাচিং ম্যাপার শেষ করবে, কারণ তাদের আলাদা ক্ষেত্র রয়েছে। তবে আপনি ভাগ করে নেওয়া এবং সাধারণভাবে ব্যবহৃত অপারেশনগুলিও শেষ করবেন। উদাহরণস্বরূপ: "শেষবারের মতো অনলাইনে দেখা" সময় আপডেট করা । এবং বিদ্যমান ম্যাপারগুলিকে আরও সংশ্লেষিত করার পরিবর্তে আরও বাস্তববাদী পদ্ধতির একটি সাধারণ "ইউজার ম্যাপার" রাখা উচিত যা কেবলমাত্র সেই টাইমস্ট্যাম্পটি আপডেট করে।
কিছু অতিরিক্ত মন্তব্য:
ডাটাবেস টেবিল এবং মডেল
কখনও কখনও বৃহত্তর প্রকল্পগুলিতে ডাটাবেস টেবিল, ডোমেন অবজেক্ট এবং ম্যাপারের মধ্যে সরাসরি 1: 1: 1 সম্পর্ক থাকে তবে এটি আপনার প্রত্যাশার চেয়ে কম সাধারণ হতে পারে:
একটি একক ডোমেন অবজেক্ট দ্বারা ব্যবহৃত তথ্য বিভিন্ন টেবিল থেকে ম্যাপ করা যেতে পারে, যখন অবজেক্টের নিজেই ডাটাবেসে কোনও অধ্যবসায় নেই।
উদাহরণ: আপনি যদি একটি মাসিক প্রতিবেদন তৈরি করে থাকেন। এটি বিভিন্ন টেবিলের থেকে তথ্য সংগ্রহ করবে, তবে MonthlyReport
ডাটাবেসে কোনও যাদুকরী টেবিল নেই ।
একটি একক ম্যাপার একাধিক টেবিলকে প্রভাবিত করতে পারে।
উদাহরণ: আপনি যখন User
বস্তুটি থেকে ডেটা সংরক্ষণ করছেন , তখন এই ডোমেন অবজেক্টে অন্যান্য ডোমেন অবজেক্টগুলি - Group
দৃষ্টান্তগুলির সংকলন থাকতে পারে । আপনি যদি এগুলি পরিবর্তন করেন এবং সঞ্চয় করেন User
তবে ডেটা ম্যাপারকে একাধিক সারণীতে আপডেটগুলি প্রবেশ করতে হবে এবং / অথবা প্রবেশ সন্নিবেশ করতে হবে।
একক ডোমেন অবজেক্টের ডেটা একাধিক টেবিলের মধ্যে সংরক্ষণ করা হয়।
উদাহরণ: বৃহত সিস্টেমে (ভাবেন: একটি মাঝারি আকারের সামাজিক নেটওয়ার্ক), এটি ব্যবহারকারীর প্রমাণীকরণ ডেটা এবং প্রায়শই অ্যাক্সেস করা ডেটা বৃহত্তর সামগ্রীর থেকে পৃথকভাবে অ্যাক্সেস করা তথ্য ব্যবহারের হতে পারে, যা খুব কমই প্রয়োজন হয়। User
সেক্ষেত্রে আপনার কাছে এখনও একটি একক শ্রেণি থাকতে পারে , তবে এতে থাকা তথ্য সম্পূর্ণ বিবরণী এনেছে কিনা তা নির্ভর করবে।
প্রতিটি ডোমেন অবজেক্টের জন্য একাধিক ম্যাপার থাকতে পারে
উদাহরণ: আপনার কাছে জনসাধারণের মুখোমুখি এবং পরিচালনা সফ্টওয়্যার উভয়ের জন্য একটি শেয়ারড কোডবেসযুক্ত একটি নিউজ সাইট রয়েছে। তবে, উভয় ইন্টারফেস একই Article
বর্গ ব্যবহার করার সময় , পরিচালনায় এতে আরও অনেক বেশি তথ্য প্রয়োজন। এই ক্ষেত্রে আপনার দুটি পৃথক ম্যাপার থাকবে: "অভ্যন্তরীণ" এবং "বাহ্যিক"। প্রতিটি পৃথক অনুসন্ধান সম্পাদন করে, বা এমনকি বিভিন্ন ডেটাবেস ব্যবহার করে (মাস্টার বা দাস হিসাবে)।
একটি ভিউ কোনও টেম্পলেট নয়
এমভিসিতে দৃষ্টান্তগুলি দেখুন (আপনি যদি প্যাটার্নের এমভিপি প্রকরণটি ব্যবহার না করেন) বর্তমান তর্কটির জন্য দায়ী। এর অর্থ হ'ল প্রতিটি ভিউ সাধারণত কমপক্ষে কয়েকটি টেমপ্লেট জগল করে। এটি মডেল স্তর থেকে ডেটা অর্জন করে এবং তারপরে, প্রাপ্ত তথ্যের উপর ভিত্তি করে একটি টেম্পলেট চয়ন করে মান নির্ধারণ করে।
এ থেকে আপনি যে উপকার পেয়েছেন তার মধ্যে একটি হ'ল পুনরায় ব্যবহারযোগ্য। আপনি যদি কোনও ListView
শ্রেণি তৈরি করেন , তবে, ভাল-লিখিত কোড সহ, আপনি একই শ্রেণীর ব্যবহারকারীর তালিকা এবং নিবন্ধের নীচে মন্তব্যগুলির উপস্থাপনা হস্তান্তর করতে পারেন। কারণ তাদের দুজনেরই একই উপস্থাপনা যুক্তি রয়েছে। আপনি কেবল টেমপ্লেটগুলি স্যুইচ করুন।
আপনি হয় স্থানীয় পিএইচপি টেম্পলেট ব্যবহার করতে পারেন বা কিছু তৃতীয় পক্ষের টেম্প্লেটিং ইঞ্জিন ব্যবহার করতে পারেন । কিছু তৃতীয় পক্ষের গ্রন্থাগারও থাকতে পারে, যা দর্শন দৃষ্টান্তগুলিকে পুরোপুরি প্রতিস্থাপন করতে সক্ষম ।
উত্তরের পুরানো সংস্করণটি কী?
একমাত্র বড় পরিবর্তনটি হ'ল, পুরানো সংস্করণে যাকে মডেল বলা হয় , এটি আসলে একটি পরিষেবা । বাকি "লাইব্রেরির সাদৃশ্য" বেশ ভাল রাখে।
আমি যে ত্রুটিটি দেখছি তা হ'ল এটি একটি সত্যই অদ্ভুত গ্রন্থাগার হবে কারণ এটি আপনাকে বই থেকে তথ্য ফিরিয়ে দেবে, তবে আপনাকে বইটি নিজেই স্পর্শ করতে দেবে না, অন্যথায় বিমূর্ততা "ফুটো" হতে শুরু করবে। আমি আরও উপযুক্ত উপমা সম্পর্কে চিন্তা করতে পারে।
দর্শন এবং নিয়ন্ত্রণকারী দৃষ্টান্তগুলির মধ্যে সম্পর্ক কী ?
এমভিসি কাঠামো দুটি স্তর নিয়ে গঠিত: ইউআই এবং মডেল। ইউআই স্তরের প্রধান কাঠামো হল ভিউ এবং নিয়ামক।
আপনি যখন এমভিসি ডিজাইনের প্যাটার্ন ব্যবহার করে এমন ওয়েবসাইটগুলি নিয়ে কাজ করছেন, তখন সর্বোত্তম উপায় হল ভিউ এবং নিয়ন্ত্রণকারীদের মধ্যে 1: 1 সম্পর্ক থাকা। প্রতিটি দর্শন আপনার ওয়েবসাইটের একটি পুরো পৃষ্ঠা প্রতিনিধিত্ব করে এবং নির্দিষ্ট ভিউয়ের জন্য আগত সমস্ত অনুরোধগুলি পরিচালনা করতে এটির একটি উত্সর্গীকৃত নিয়ামক রয়েছে।
উদাহরণস্বরূপ, একটি খোলার নিবন্ধ উপস্থাপন করতে, আপনি \Application\Controller\Document
এবং ছিল \Application\View\Document
। এটিতে ইউআই স্তরের সমস্ত মূল কার্যকারিতা থাকবে, যখন নিবন্ধগুলি নিয়ে কাজ করার বিষয়টি আসে (অবশ্যই আপনার কিছু এক্সএইচআর উপাদান থাকতে পারে যা নিবন্ধের সাথে সরাসরি সম্পর্কিত নয়) ।