PHP Template Engine - SilverRiver

Silver River Logo
Silver River Logo


بسم الله.

چند ماهی میشه که روی یک پروژه خارجی درحال کار هستم که نیازمند یک فریم ورک مثل Laravel بود که با پیشنهاد مدیر پروژه اون فریم ورک گذاشتم کنار و نشستم خودم از پایه یک فریم ورک MVC طراحی کردم که این کتابخونه یکی از کتابخونه های این فریم ورکه.😊

این اواخر تصمیم گرفتم این کتابخونه سادرو عمومی منتشر کنم ، شاید بدرد کسی خورد.

سینتکس شبیه به blade داره که البته فرق هایی داره فقط کلیتش شبیه این موتور هست و اینکه در این موتور میشه عناصر و اتریبیوت های سمت سرور ایجاد کرد که همه این ها به صورت تو در تو (nested) قابل استفاده هستن.

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

موتور دارای یک حافظه مشترک (share) هست که میشه از اون برای انتقال داده ها بین صفحات و غیره استفاده کرد.استفاده ازش خیلی ساده است (شایدم برای خودم که نوشتمش ساده است 😁 🤷‍♂️) ، همه توابع ساخت Directive ها و عناصر و غیره از هم تفکیک شدن و رندر کردن فایل هم سادست ، سیستم کش هم همونطور که گفتم داخل خود سیستم تعبیه شده و کاری نیاز نیست انجام بدید. (البته توابعی برای دسترسی استفاده از اون رو دارید 😉)

خوب بزارید درباره سینتکس بگم ، اگه لازم داشتید آموزش استفاده توی گیتهاب هست. 😁

لینک پروژه در گیتهاب

اول از همه Directive ها هستن که تا حدی شبیه به blade هستن با کمی اضافات.

دو نوع دیرکتیو داریم.

  1. inline directive
  2. block directive

نوع اول یا درون خطی ، با فرمت زیر نوشته میشه:

@[A NAME]( [ARGUMENT] )

با @ شروع میشه ، یک نام داره که قبلا هندلر اون ثبت شده و ورودی های اون، که همگی ورودی ها به صورت یک string به تابع هندلر ارسال میشه. لیست آرگومان ها به صورت اختیاریه و میتونید اگر نیاز نیست ، ننویسید.


نوع دوم بلاکی هست. که فرمت ، همون فرمت بالاست با این تفاوت که یک نماد انتهایی هم داره:

@[NAME]( [ARGUMENT] ) [...CONTENT...] @end[NAME]

در این مورد، تابع هندلر ، لیست آرگومان ها ،درصوت وجود، دریافت می کنه و همچنین محتوای درون بلاک که قبلا رندر شده.

رندرینگ قالب از داخلی ترین شروع میشه و به بالا برمیگرده.

در دو نوع بالا ما یک نوع دیگه هم داریم که بین هردو مشترکه. در این حالت فقط می تونیم یک حالت خروجی داشته باشه که بجای این تمپلیت ها قرار میگیره. اما اگه بخوایم به صورت تو درتو استفاده کنیم چی؟

مثلا این طوری:

@if( @auth.name == "porya" )
    hello porya
@endif

در این حالت خروجی PHP به این صورت میشه:

<?php if( <?php echo Auth::name(); ?> == "porya" ){ ?>
    hello porya
<?php } ?>    

خوب قطعا این کد خطا داره. خوب پس باید راه دیگه ای باشه که این مشکل پیش نیاد.

پس تصمیم گرفتم این قرارداد رو انتخاب کنم که اگر دو @ پشت سر هم اومد ، یعنی قراره حالت دیگه اجرا بشه ، مثلا خروجی تابع به جای اینکه داخل بلاک PHP باشه می تونه کد مستقیم PHP باشه، یعنی:

@if( @@auth.name == "porya" )
     hello porya 
@endif

که میشه این:

<?php if( Auth::name() == "porya" ){ ?>
        hello porya 
<?php } ?>

البته اینکه چه خروجی باشه باز هم از طریق همون تابع هندلر قابل مشخص کردنه که بستگی به دولوپر داره.

خوب این از دیرکتیو ها. مورد بعدی عناصر هستن. عناصر سرور ، دقیقا مثل عناصر HTML هستن با این تفاوت که داخل قسمت تعریف HTML نمی شه جز اتریبیوت ، چیز دیگه نوشت و البته اینکه نام عناصر باید با `server:` شروع بشه و البته دوم هم اینکه این تگ ها سمت سرور پردازش میشن.

مثلا :

<server:myTag />

در این موتور عناصر و تگ ها به صورت مجزا قابل تعریف هستن. مثال بالا یک تگ بود.

این مثال یک عنصره:

<server:row  cols="5">
        it is a .row div with 5 same column (for example)
</server:row>

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

مورد بعدی مشخصه ها هستن. مشخصه های سرور در تمامی کد html قابل استفاده هستن. یعنی موتور اصلا متوجه نمیشه که این مشخصه سرور داخل یک عنصر غیر سرور هست یا نه. تنها جایی که متوجه میشه ، استفاده از اون در عناصر و تگ های سرور هست. در تگ های سرور خروجی رندر اتریبیوت ها مستقیم توی صفحه جایگذاری نمیشه (برخلاف استفاده خارج از تگ های سرور) ، به صورت آرایه از اتریبیوت ها در هندلر در دسترس هستن که شی ای از کلاس AttributeWrapper هستن . در این لینک می تونید نمونه از استفاده از اتریبیوت هارو ببینید.

مشخصه های (attribute) سرور هم مثل تگ های سرور مشخص میشن. یعنی باید اول اسم مشخصه از `server:` استفاده بشه. در خارج از تگ های سرور میتونید این کلمه sever رو با یک `\` اسکیپ کنید و موتور اونو به عنوان مشخصه نمی خونه.مثلا:

this example is an engine attribute: \server:name="value"

البته به جای `:` هم می تونید از کد شده اون در html استفاده کنید یعنی این کد :

server:name="value"

نکته ای که در باره این مشخصه ها وجود داره اینکه ، نحوه خروجی مشخصه ها که چه چیزی به جای اونا نوشته بشه در تگ های سرور که دست دولوپره ، اما در قسمت های دیگه خروجی به این صورته که از نام مشخصه کلمه `server:` حذف میشه و مقدار خروجی تابع به جای مقدار value این مشخصه قرار میگیره:

server:int="123.545"      will convert to (for example) :     int="123"

خوب میرسیم به آخرین مورد در سینتکس. اجرا کننده های درون خطی. که با علامت `{{ ... }}` مشخص میشه.

هر چیزی که بین کلوشه ها نوشته بشه باید در فرمت php باشه و خروجی اون چاپ میشه در صفحه. البته این سینتکس خودش چند دسته داره که این موارده:

  • ( @@{{ ... }} ) = htmlentities(...)
  • ( @!{{ ... }} ) = ...
  • ( @{{ ... }} ) = <?php echo htmlentities(...); ?>
  • ( !{{ ... }} ) = <?php ... ?>
  • ( {{ ... }} ) = <?php echo ... ; ?>

خوب ، این یک خلاصه ی کامل از چیزی بود که هست. 😅

فقط مونده تعریف کردن موارد بالا که توابعشون چی هست که داخل گیتهاب مثال هاش هست و اینکه اصلا چجوری اضافه کنیم به پروژه و چجوری رندر بگیریم و اینکه سیستم کش چجوریه.

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

و اینکه قلت املاعی چیظی دیدین بح بذرگواری خدطون ببخشین.از بچگی مشکل املاع داشطم 😁

موفق باشی خواننده عزیز. 😉


https://github.com/poryagrand/SilverRiver