থিম
অধ্যায় ১: প্যাকেজ আর্কিটেকচার এবং কম্পোজার ইন্টারনালস
প্যাকেজের কোনো নিজের Kernel নেই; এটি হোস্ট অ্যাপ্লিকেশনের HTTP Kernel ও Console Kernel এর ওপর কাজ করে। তাই আর্কিটেকচার বানানোর সময় আমাদের বুঝতে হবে কীভাবে অ্যাপ কোর বুট হয়, কীভাবে কম্পোজার ক্লাসলোডার ক্লাস রেজল্ভ করে, এবং কীভাবে লারাভেল প্যাকেজকে অটো-ডিসকভার করে রানটাইমে ইনজেক্ট করে। এই অধ্যায়ে আমরা সেই লো-লেভেল জিনিসগুলো একটু আলোচনা করবো ইনশাল্লাহ।
১.১ প্যাকেজ বনাম অ্যাপ্লিকেশন
অ্যাপ্লিকেশন নিজস্ব .env, public/index.php, App\Http\Kernel ও App\Console\Kernel নিয়ে বুট হয়। প্যাকেজ কেবলমাত্র ডিপেন্ডেন্সি ইনজেকশন, সার্ভিস প্রভাইডার ও কনফিগ/রাউট নেমস্পেস দিয়ে হোস্ট অ্যাপে যুক্ত হয়; কোনো এন্ট্রি পয়েন্ট বা Kernel নেই।
১.১.১ হোস্ট Kernel ফ্লো
php
// public/index.php -> bootstrap/app.php -> resolveKernel(HttpKernelContract)
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);bootstrap/app.phpঅ্যাপ অবজেক্ট তৈরি করে, Config ক্যাশ লোড করে, এবংApplication::registerConfiguredProviders()কল করে।- এই
registerConfiguredProviders()ফাংশনbootstrap/cache/packages.php(প্যাকেজ ম্যানিফেস্ট) পড়ে অটো-ডিসকভার্ড প্রোভাইডারগুলো রেজিস্টার করে; এখানেই আপনার প্যাকেজ বুট হয়। - প্যাকেজ কোনো নিজস্ব middleware stack বানায় না;
App\Http\Kernel::$middlewareGroupsএর মধ্যে আপনার প্যাকেজের middlewareRoute::middlewareবাapp('router')->aliasMiddlewareদিয়ে যোগ করতে হয়।
১.১.২ রেসপন্সিবিলিটি বাউন্ডারি
- কনফিগ স্পেস:
config/invoicelite.phpএর মতো নিজস্ব প্রিফিক্স ব্যবহার করুন। হোস্টেরconfig/app.phpমিউটেট করবেন না। - রাউট/ভিউ নেমস্পেস: রাউট নেমে
invoicelite.এবং ভিউতেinvoicelite::ব্যবহার করুন— যাতে করে হোস্ট এপ্লিকেশনের রাউট/ভিউয়ের সাথে ক্ল্যাশ না করে। - স্টেট/ফাইল: প্যাকেজ
storage_path('app/vendor/invoicelite')বা পাবলিশডpublic/vendor/invoiceliteছাড়া অন্য কোথাও লিখবে না। Kernel-লেভেল লগ/সেশন হোস্টই ম্যানেজ করে।
১.২ কম্পোজার অটোলোডিং: PSR-4 থেকে ClassLoader পর্যন্ত
প্যাকেজের প্রতিটি ক্লাস কীভাবে খুঁজে পায় কম্পোজার, সেটি না বুঝলে Class not found বা ভুল নেমস্পেসের সমস্যা ডিবাগ করা কঠিন।
১.২.১ PSR-4 ম্যাপের শারীরবৃত্ত
composer.json:
json
{
"name": "devmaster/invoicelite",
"autoload": {
"psr-4": {
"DevMaster\\InvoiceLite\\": "src/"
},
"files": [
"src/helpers.php"
]
}
}composer dump-autoloadচালালেvendor/composer/autoload_psr4.phpএ এমন এন্ট্রি হয়:
php
return [
'DevMaster\\InvoiceLite\\' => [__DIR__.'/../..'.'/packages/DevMaster/InvoiceLite/src'],
];filesসেকশনে দেয়া হেল্পার ফাইলগুলো ক্লাসলোডার ইগার-লোড করে (require)—পরবর্তীতে ফাংশন না পেলে Fatal হবে না।
১.২.২ ClassLoader কিভাবে ক্লাস খোঁজে
php
// vendor/composer/ClassLoader.php
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file); // @include, not require_once
return true;
}
return null;
}findFileপ্রথমে PSR-4 প্রিফিক্স ম্যাপ দেখে পাথ গঠন করেsrc/InvoiceManager.phpখুঁজে।composer dump-autoload -oদিলে আগেই ক্লাসম্যাপ তৈরি হয় (autoload_classmap.php), ফলেfindFileপ্রথমেই ক্লাসম্যাপ লুকআপ করে ডিস্ক স্ক্যান এড়ায়।- বড় প্যাকেজে
composer install --optimize-autoloader --classmap-authoritativeদিলে অননুমোদিত পাথ স্ক্যান বন্ধ থাকে; ভুল নেমস্পেস থাকলে সাথে সাথেই ধরা পড়ে।
১.২.৩ Composer Cache/Lock ইন্টারনাল
- Path repository ব্যবহার করলে
vendor/composer/installed.phpএ আপনার প্যাকেজdev-masterবাdev-mainহিসেবে লেখা হয়,install_pathএ সিমলিংক পয়েন্ট থাকে। composer.lockহোস্ট অ্যাপেই থাকবে; প্যাকেজ রিপোতে নয়। তাই আপনার প্যাকেজের ভার্সন আপগ্রেড করতে হলে হোস্ট অ্যাপেcomposer update devmaster/invoiceliteচালাতে হবে।
১.৩ লারাভেল প্যাকেজ অটো-ডিসকভারি ও ম্যানিফেস্ট ক্যাশ
লারাভেল হোস্ট অ্যাপ প্যাকেজ ম্যানিফেস্ট ক্যাশ করে যাতে প্রতিটি রিকোয়েস্টে composer.json স্ক্যান করতে না হয়।
১.৩.১ composer.json এ অটো-ডিসকভারি
json
{
"extra": {
"laravel": {
"providers": [
"DevMaster\\InvoiceLite\\InvoiceLiteServiceProvider"
],
"aliases": {
"InvoiceLite": "DevMaster\\InvoiceLite\\Facades\\InvoiceLite"
}
}
}
}১.৩.২ PackageManifest কী করে?
php
// vendor/laravel/framework/src/Illuminate/Foundation/PackageManifest.php
public function providers()
{
return $this->config('providers', []);
}
protected function build()
{
$packages = $this->getPackages(); // composer installed.json পড়ে
$ignore = $this->config('dont-discover', []);
foreach ($packages as $package => $config) {
if ($this->shouldIgnore($package, $ignore)) continue;
$manifest['providers'] = array_merge(
$manifest['providers'], $config['extra']['laravel']['providers'] ?? []
);
$manifest['aliases'] = array_merge(
$manifest['aliases'], $config['extra']['laravel']['aliases'] ?? []
);
}
$this->write($manifest); // bootstrap/cache/packages.php
}php artisan package:discoverএইbuild()রান করেbootstrap/cache/packages.phpফাইল তৈরি করে।- HTTP Kernel বুটের সময়
Application::registerConfiguredProviders()এই ক্যাশ পড়ে প্রোভাইডার রেজিস্টার করে; আপনার প্যাকেজ তখনই কন্টেইনারে bind/load হয়।
১.৩.৩ ক্যাশ ইস্যু ডিবাগ
- নতুন প্রোভাইডার/এলিয়াস যোগ করে কাজ না করলে
php artisan package:discover --ansi. - অদ্ভুত ক্যাশ সমস্যায়
rm bootstrap/cache/packages.php && php artisan package:discover. - Route/config ক্যাশ পুরোনো হলে নতুন রাউট/কনফিগ দেখা যাবে না, তাই ডিপ্লয়ের সময়
php artisan config:cache && php artisan route:cacheরিফ্রেশ করুন।
১.৪ বেস্ট প্র্যাকটিস: আইসোলেশন, ডিপেন্ডেন্সি, Kernel কোঅপারেশন
১.৪.১ নেমস্পেস/নেমিং ডিসিপ্লিন
- সব কনফিগ/রাউট/ইভেন্ট/জব নাম প্রিফিক্স করুন:
invoicelite.*. - ভিউ সবসময়
loadViewsFromদিয়ে লোড করুন, এবং ব্লেড কলেinvoicelite::.... - ডাটাবেস টেবিল নাম কনফিগ-ড্রিভেন বা প্রিফিক্সড রাখুন (৭ম অধ্যায়ে বিস্তারিত)।
১.৪.৩ Kernel কোঅপারেশন (প্যাকেজের নিজস্ব Kernel নেই)
- Middleware যুক্ত করতে হলে হোস্ট রাউট গ্রুপে কনফিগ-ড্রিভেন মিডলওয়্যার দিন:
Route::middleware(config('invoicelite.middleware', ['web'])). - কনসোল কমান্ড/সিডার/শিডিউল সবই হোস্ট
ConsoleKernelএর মাধ্যমে চলে;app()->runningInConsole()চেক দিয়ে শর্তসাপেক্ষে রেজিস্টার করুন। - কোনো গ্লোবাল exception handler পরিবর্তন করবেন না; প্রয়োজনে আপনার প্যাকেজের এক্সেপশন রূপান্তর করতে middleware বা custom handler ক্লাস ব্যবহার করুন।
১.৪.৪ আপগ্রেড/ব্রেকিং চেঞ্জ চেকলিস্ট
- ব্রেকিং কনফিগ কি পরিবর্তন করলে
UPGRADE.mdদিন এবং ডিফল্ট ভ্যালু রেখে fallback রাখুন। - অটো-ডিসকভারি এন্ট্রি পরিবর্তন করলে ডকুমেন্ট করুন; নইলে পুরোনো ক্যাশ লোড হতে পারে।
- পাবলিশড ফাইলের পাথ বদলালে নতুন ট্যাগ নাম দিন।