Skip to content

অধ্যায় ১: প্যাকেজ আর্কিটেকচার এবং কম্পোজার ইন্টারনালস

প্যাকেজের কোনো নিজের Kernel নেই; এটি হোস্ট অ্যাপ্লিকেশনের HTTP KernelConsole Kernel এর ওপর কাজ করে। তাই আর্কিটেকচার বানানোর সময় আমাদের বুঝতে হবে কীভাবে অ্যাপ কোর বুট হয়, কীভাবে কম্পোজার ক্লাসলোডার ক্লাস রেজল্ভ করে, এবং কীভাবে লারাভেল প্যাকেজকে অটো-ডিসকভার করে রানটাইমে ইনজেক্ট করে। এই অধ্যায়ে আমরা সেই লো-লেভেল জিনিসগুলো একটু আলোচনা করবো ইনশাল্লাহ।

১.১ প্যাকেজ বনাম অ্যাপ্লিকেশন

অ্যাপ্লিকেশন নিজস্ব .env, public/index.php, App\Http\KernelApp\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 এর মধ্যে আপনার প্যাকেজের middleware Route::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 রাখুন।
  • অটো-ডিসকভারি এন্ট্রি পরিবর্তন করলে ডকুমেন্ট করুন; নইলে পুরোনো ক্যাশ লোড হতে পারে।
  • পাবলিশড ফাইলের পাথ বদলালে নতুন ট্যাগ নাম দিন।

সৎ ক্রেডিট: লেখক AI, সম্পাদক আবুল হাসান