همونطور که همه تون میدونید برای توابع و کلاس های PHP از PHPDoc استفاده می کنیم. یه چیزی شبیه این :

/**
* A summary informing the user what the associated element does.
*
* A *description*, that can span multiple lines, to go _in-depth_ into the details of this element
* and to provide some background information or textual references.
*
* @param string $myArgument With a *description* of this argument, these may also
*    span multiple lines.
*
* @return void
*/
function myFunction($myArgument)
{
    // ...
}

فواید و کاربرد ها

در هر DocBlock اطلاعات مختلفی در مورد اون تابع یا کلاس ذکر میشه که در خیلی موارد کاربرد هایی داره. مثلا فرض کنید بعد از 5 سال برمیگردید سراغ یه پروژه و میخواید یه ویژگی جدید بهش اضافه کنید یا یه قسمت رو تغییر بدید ، مسلما کدهایی که اون زمان نوشتید رو الان متوجه نمیشید و نمیفهمید که هدف از نوشتن این تابع چی بوده یا پارامتر هاش چه کاربرد هایی داره. یه مثال بهتر ، یکی دیگه از مهم ترین کاربرد ها وقتیه که شما میخواید یه سرویس ارائه بدید. پروژه ای دارید و در کنار داشبورد اون پروژه برای مشتری هاتون یک API تهیه می کنید. با ایجاد این DocBlock ها می تونید به کاربرهاتون توی درک بهتر کد ها و توابع کمک بدید.

راه حل ؟

خب مسلما اولین مرحله نوشتن خود DocBlock هاست. در این پست به این موضوع اشاره ای نمیشه و فرض رو بر این میگیرم که تمام بلاک هاتون رو نوشتید.

وقتی یه پروژه خیلی بزرگ دارید ، نباید از کاربر انتظار داشته باشید که بیاد و کل کلاس ها و فایل ها و تابع ها رو بررسی کنه. راه های ساده تری هم برای این کار وجود داره. اونم خروجی گرفتن از این بلاک هاست. برای این کار کتابخانه های مختلفی وجود داره که تقریبا همه شون رو بررسی کردم چند وقت اخیر. یکی از بهترین کتابخانه ها برای این کار Sami بود که الان میخوایم با اون این کار رو انجام بدیم.

پروژه متن باز این کتابخانه رو میتونید از این لینک مشاهده کنید.

روش استفاده از این کتابخانه خیلی راحته. توجه داشته باشید که Sami در اصل یک ابزار حساب میشه ، بنابراین نیاز نیست به صورت یه کتابخانه مجزا منتشر بشه که مثلا از طریق composer نصب و استفاده کنید توی پروژه. پس :

  1. فایل اجرایی کتابخانه رو دانلود کنید و تو پوشه اصلی پروژه بذارید : curl -O http://get.sensiolabs.org/sami.phar
  2. جهت تست کتابخانه ، اونو بدون هیچ آرگومانی اجرا کنید : php sami.phar

در این مرحله ، Sami آماده استفاده است. برای استفاده از Sami باید یه فایل جهت تنظیمات پروژه تون ایجاد کنید. فایلی به نام sami.config.php در root پروژه ایجاد کنید و کدهای زیر رو در اون قرار بدید :

<?php

use Sami\RemoteRepository\GitHubRemoteRepository;
use Sami\Sami;
use Symfony\Component\Finder\Finder;

$iterator = Finder::create()
    ->files()
    ->name("*.php")
    ->exclude("node_modules")
    ->exclude("resources")
    ->exclude("database")
    ->exclude("config")
    ->exclude("routes")
    ->exclude("bootstrap")
    ->exclude("storage")
    ->exclude("vendor")
    ->in($dir = __DIR__ . "/app");

return new Sami($iterator, [
    "theme" => "default",
    "title" => "Title",
    "build_dir" => __DIR__ . "/docs/documents",
    "cache_dir" => __DIR__ . "/docs/cache",
    'remote_repository' => new GitHubRemoteRepository('username/repository', dirname($dir)),
    'default_opened_level' => 2
]);

تنظیمات خیلی ساده ای وجود داره و اونقدر ها پیچیده نیست. از ()Finder::create جهت ساخت یه جور جستجوگر استفاده می کنیم و بهش میگیم که دقیقا دنبال کدوم فایل ها می گردیم.

برای مثال در این تنظیماتی که من نوشتم گفتم که تمام فایل ها با پسوند PHP مد نظر من هست و البته در پوشه های ذکر شده مانند node_modules یا vendor یا موارد ذکر شده دیگه لازم نیست دنبالشون بگردی. برای مثال داخل یه پوشه یه سری فایل قرار دادید که ب صورت Helper عمل میکنن و نیازی به DocBlock ندارن و شماهم چیزی ننوشتید براش ، پس خیلی راحت میتونید اون پوشه و محتویاتش رو exclude کنید.

بعد از اینکه جستجوگر رو تنظیم کردیم ، یک instance از Sami بر میگردونیم که میتونیم یه سری تنظیمات کلی انجام بدیم. برای مثال قالب خروجی ، نام پروژه ، دایرکتوری های خروجی ، ریپازیتوری گیت و ...

بعد از اینکه فایل رو تنظیم کردید با اجرای دستور زیر ، مستندات شما آماده میشه :

php sami.phar update sami.config.php

اگر به دایرکتوری که در تنظیمات instance آدرس دهی کرده اید مراجعه کنید فایل های نهایی رو میتونید ببینید ( فایل index را اجرا کنید ).

مشکلات بعدی

وقتی به این مرحله از کار برسیم ، همه چیز آماده شده و خیلی راحت کار میکنه. ولی یه مشکل اساسی هست ، و چه مشکلی بزرگتر از تنبلی !!!

توابع و کلاس ها مدام در حال تغییر هستند و خودم به شخصه حوصله ندارم هر سری یه کنسول باز کنم و دستور رو اجرا کنم

مشکل دوم ، خیلی ها برای مستند سازی پروژه هاشون یه ریپازیتوری جدا دارن ( مثل خودم ). پس هر سری باید مستندات رندر بشه ، کپی بشه اونور ؟ مسلما نه

اول از همه بریم مشکل کپی کردن رو حل کنیم. اگه به تنظیمات instance مراجع کنید دو مقدار build_dir و cache_dir رو می بینید. گفتیم که از این مقادیر جهت آدرس دهی دایرکتوری خروجی استفاده میشه. با فرض اینکه تمام ریپازیتوری ها در یه پوشه clone شده ، میتونیم این دو مقدار رو به این صورت تنظیم کنیم :

"build_dir" => __DIR__ . "/../Another_rep/documents",
"cache_dir" => __DIR__ . "/../Another_rep/cache",

توجه داشته باشید که حتما باید توی پوشه های جداگانه تنظیم بشن ، مثلا شما نمیتونید build_dir رو مستقیم به روت ریپازیتوری آدرس دهی کنید. چرا ؟ چون هر سری که Sami اجرا بشه ، محتوا پوشه مقصد رو کامل پاک میکنه و این یعنی اینکه پوشه git. شما که تنظیمات ریپازیتوری توش قرار داره پاک میشه ( البته پاک که نمیشه چون permission error داده میشه ولی به هر حال ... ) پس یادتون باشه که پوشه های جدا تنظیم کنید !!

این از رفع مشکل کپی کردن ...

مشکل بعدی اینکه خب حالا مستندات ما رندر شد و ریپازیتوریش هم آپدیت شد ، کی میخواد بره اونور تغییرات رو commit و push کنه ؟؟؟ بیایم اینم اتوماتیک کنیم !
بسته به نوع سیستم عامل میتونید یه اسکریپت اجرایی بنویسید و کار خودتون رو راحت کنید. برای مثال من این اسکریپت رو نوشتم و اونو تو فایل generate_docs.bat ذخیره کردم :

@echo off

php sami.phar update sami.config.php

cd ../Another_rep

git commit . -m "Update docs"

git push

فکر نکنم نیاز به توضیح داشته باشه و کد ها کاملا قابل فهمه. خب ... اینم از حل اولین مرحله از مشکل تنبلی

:::caution
اگه برای Git از امضای دیجیتالی ( GPG ) استفاده می کنید از این دستور برای commit کردن استفاده کنید :

git commit -S . -m "Update docs"

بیشتر بخوانید : امضای دیجیتالی Commit ها در گیت
:::

الان دیگه میشه با اجرای این فایل خیلی راحت همه مراحل رو اتوماتیک انجام بدید. ولی بیایم کمی تنبل تر باشیم !!! وقتی داریم کد میزنیم و تغییرات رو ایجاد میکنیم ، نیاز نیست بریم فایل رو اجرا کنیم. بیاید همین کار رو از طریق IDE انجام بدیم ! چطوری ؟ حتما میگید که بیایم یه Run/Debug Configuration تنظیم کنیم. خیر ! تمام IDE های ساخت JetBrains بخشی دارن به اسم External Tools که نعمت بزرگیه واقعا ! اولین بار وقتی باهاش آشنا شدم که میخواستم پروژه Jekyll خودم رو مستقیم از طریق IntelliJ اجرا کنم و دیدم کلا Run Configuration برای این کار ساخته نشده !!!

خب ، برای ساخت یه ابزار اجرایی جدید میریم به بخش Tools > External Tools و یه ابزار جدید با این تنظیمات می سازیم :

خیلی ساده بهش میگیم که بیا فایل اسکریپت من رو اجرا کن ! به همین راحتی. تنظیمات رو ذخیره میکنیم و همه چیز رو میبندیم. حالا هر بار که خواستید میتونید با مراجعه به منوی Tools و زیرمنوی External Tools ابزار نوشته شده رو اجرا کنید و ببینید که همه چیز به صورت اتوماتیک انجام میشه !

  1. آخرین تغییرات رندر گرفته میشه
  2. فایل ها به ریپازیتوری مستندات فرستاده میشه
  3. تغییرات ریپازیتوری مستندات commit و push میشه

و اینک کارها چه ساده شد ...

نتیجه

تنبلی همیشه بد نیست و یکی از راه های پیشرفت و یادگیری چیزهای جدیده. در نهایت نظر ، پیشنهاد یا هر مشکلی داشتید رو باهام در میون بذارید.