Skip to content

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

প্যাকেজের কোনো নিজের 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 এর মধ্যে আপনার প্যাকেজের 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 রাখুন।
  • অটো-ডিসকভারি এন্ট্রি পরিবর্তন করলে ডকুমেন্ট করুন; নইলে পুরোনো ক্যাশ লোড হতে পারে।
  • পাবলিশড ফাইলের পাথ বদলালে নতুন ট্যাগ নাম দিন।