۹ دی، ۱۴۰۰

١ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم معرفی فریم ورک gRPC نوشت.

در این مقاله می خواهیم به معرفی فریم ورک متن باز Remote Procedure Call (RPC) بپردازیم، همانطور که از نام آن پیدا است این فریم ورک برای ارتباط بین دستگاه‌ها، برنامه‌های کاربردی تلفن همراه و مرورگرها قابل اجرا است، در ادامه به شرح کامل آن می پردازیم.

معرفی gRPC

PRC که مخفف Remote Procedure Call می باشد، یک پروتکل برای فراخوانی یک سرویس از یک برنامه، داخل یک برنامه دیگر است. یعنی برنامه A برای اینکه یه فانکشنی داخل برنامه B رو بتونه فراخوانی کنه از این پروتکل استفاده میکنه، پس تا اینجا متوجه شدیم برای اینکه دوتا برنامه بخواهند بین همه دیگه دیتا ارسال و دریافت کنن از طریق این پروتکل میتوانند عمل کنن.

نکته: این را همه در نظر داشته باشید این ارتباط در پروتکل TCP/IP بر روی لایه Application از طریق HTTP2 اطلاعات را ارسال و دریافت می کند.

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

همانطور که در تصویر بالا مشاهده می کنید یک سرویس که با زبان ++ C نوشته شده است امکان ارتباط برقرار کردن بر روی gRPC server فراهم کرده است که از طریق استانداری به نام proto باهمدیگر ارتباط برقرار کرده اند، توجه داشته باشید که این ارتباط دارای یک Proto Request و Proto Response می باشد که تعیین می کنند که بین کلاینت و سرور چه دیتای ارسال و دریافت شود.

به صورت کلی ارتباط بین سرور و کلاینت ها به صورت RESTFull می باشد که مرسوم ترین روش ارسال و دریافت اطلاعات است که از طریق پروتکل HTTP بر روی بستر شبکه این کار را انجام می دهند. در ادامه می خواهیم تفاوت بین درخواست های RESTFull , gRPC را بررسی کنیم و همچنین در کنار آن فایل proto را معرفی کنیم و اینکه gRPC چگونه ارتباط و بین کلاینت ها برقرار می کند را شرح دهیم.

آشنایی و معرفی proto

همانطور که قبلا هم اشاره کردیم برای اینکه یک درخواست و پاسخ بین سرویس ها و کلاینت ها ارسال و دریافت بشه باید یک پروتکل یا استانداری را داشته باشید، برای همین منظور یک فایل در کنار پروژه شما وجود دارد، برای اینکه بهتر متوجه شوید مثالی که گفته می شود را هم خط به خط بررسی می کنیم، در اینجا سرویسی به نام support (پشتیبانی) را داریم که امکان ارتباط برقرار کردن از طریق پروتکل RPC در آن وجود دارد، ساختار فایل آن به شکل زیر می باشد :

syntax = "proto3";

package support;

service Ticket {
    rpc CreateTicket (CreateTicketRequest) returns (TicketInfo) {}
}

message TicketInfo {
  string id = 1;
  CustomerInfo customer = 2;
  UserInfo user = 3;
  string subject = 4;
  string content = 5;
  string status = 6;
  int32 priority = 7;
  string created_at = 8;
  repeated ReplyInfo replies = 9;
  string payload = 10;
}

message CreateTicketRequest {
  string subject = 1;
  string content = 2;
  int32 priority = 3;
  CustomerInfo customer = 4;
  UserInfo user = 5;
  string payload = 6;
}

همانطور که در بالا مشاهده می کنید ساختار فایل gRPC به این شکل است، ولی این دستورات چه کاری را انجام می دهند ؟! بیاین با یک مثال پیش بریم، در اینجا می خواهیم امکان ثبت یک تیکت و پاسخش را از طریق این فایل قرارداد کنیم.

ساختار فایل

در این بخش می خواهیم خط به خط کد را باهم بررسی کنیم و ببنیم چگونه یک استاندارد برای ارتباط RPC تعریف می شود.

syntax = "proto3"

اولین چیزی که با آن مواجه می شوید این خط کد می باشد، در بحث ارتباط ها معمولا برای اینکه بروز رسانی های مختلفی انجام می شود ورژن های مختلف proto با عدد جدا می شود، در این فایل ما از proto3 برای استاندارد ارسال و دریافت اطلاعات استفاده می کنیم، پس هر کلاینت دیگر بخواهد ارتباط برقرار کند باید آن هم قوانین را طبق استاندارد proto3 نوشته باشد.

package support

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

service Ticket

به صورت ساده بخواهم این بخش را توضیح دهم برای تمام حالت های که می خواهیم این ارتباط برقرار شود باید یک متد تعریف کنیم که ورودی و خروجی مشخصی دارد، پس درون سرویسی که برای Ticket تعریف کرده ایم، به عنوان مثال می خواهیم عملیات ایجاد تیکت را از طریق RPC مشخص کنیم.

rpc CreateTicket (CreateTicketRequest) returns (TicketInfo) {}

خط کد بالا به این معنی می باشد که یک ارتباط از نوع rpc برای عملیات CreateTicket می باشد که به عنوان ورودی CreateTicketRequest را دریافت کرده و TicketInfo را برمیگرداند.

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

message TicketInfo

همانطور که در بخش متد داخل سرویس مشاهده کردین ورودی توابع و خروجی تابع مشخص شده بود، TicketInfo دقیقا خروجی هست که قرار است از عملیات ایجاد تیکت برگشت داده شود، تمام پارامتر های داخل این آبجکت طبق مدل های دیتابیس معمولا تعریف می شود یا برحسب نیاز آن را قرارداد می کنیم. پارامتر ها بر حسب نوعی که دارن مشخص شده اند. فقط یک مورد را به عنوان نکته اینجا مطرح می کنم، داخل بدنه یک پارامتر به نام CustomerInfo customer = 2 وجود دارد، خود مقدار CustomerInfo درونش یکسری پارامتر های مثل customer_key وجود دارد، این نوع تعاریف دقیقا مثل ارتباطی است که بین موجودیت ها برقرار می شود، در اینجا می خواهیم بفهمیم که تیکت فرستاده شده توسط کدام کاربر(مشتری) می باشد پس اطلاعات خود مشتری میتواند یک آبجکت جدا باشد.

message TicketInfo {
  string id = 1;
  CustomerInfo customer = 2;
  UserInfo user = 3;
  string subject = 4;
  string content = 5;
  string status = 6;
  int32 priority = 7;
  string created_at = 8;
  repeated ReplyInfo replies = 9;
  string payload = 10;
}

message CreateTicketRequest

در اینجا هم ما پارامتر های ورودی برای ثبت یک تیکت جدید مشخص کرده ایم، توجه داشته باشید که messge یک کلمه کلید می باشد و بعد آن نامی است که می خواهیم مشخص کنیم برای چه عملیات؟ چه دیتای؟ باید دریافت یا ارسال شود.

message CreateTicketRequest {
  string subject = 1;
  string content = 2;
  int32 priority = 3;
  CustomerInfo customer = 4;
  UserInfo user = 5;
  string payload = 6;
}

دقیقا تعریف ورودی های CreateTicketRequest شبیه به TicketInfo می باشد.

مقایسه RESTFull و gRPC

معمولا برای نوشتن api های که از سمت سرور می آید از معماری RESTFull استفاده می شود که از طریق پروتکل HTTP عملیات ارسال و دریافت اطلاعات انجام می شود در واقعا gRPC هم خیلی به شبیه به آن می باشد که با این تفاوت که بر روی پروتکل HTTP2 دیتا را ارسال و دریافت می کند و هم ایمن تر و سریع تر می باشد، در ادامه یکسری از مزیت های آن را مطرح می کنیم .

این پروتکل برای ارسال و دریافت اطلاعات به صورت پیش فرض برای سریالایز کردن اطلاعات از ProtocolBuffer استفاده می کنه که توسط گوگل نوشته شده.

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

یکی از خوبی های دیگ gRPC اینکه که schema تعریف شده در سمت سرور توابع ورودی و خروجی را برای کلاینت مشخص می کند. با این کار میتونیم بفهمیم چه متدهای با چه ورودی و خروجی در سمت سرور وجود دارد.

قابلیت خوب دیگ اینکه Bi-directional Streaming برای جریانی از داده ها استفاده میکنه، به این معنی که ارسال و دریافت اطلاعات به صورت همه زمان صورت می گیرد پس برای کار با داده های مثل فیلم بسیار مناسب است.

اخرین مورد که قبلا هم اشاره کردیم اینکه بر روی پروتکل HTTP2 ارسال و دریافت اطلاعات انجام میدهد که خیلی امن و سریع می باشد.

در نهایت این فریم ورک توسط گوگل نوشته شده است و توسط شرکت های بسیار مطرح که در پایین اشاره می شود مورد استفاده قرار گرفته است.

اگر نیاز به تست درخواست های RPC خود داشتید میتوانید نرم افزار BloomRPC را نصب کنید.

توجه داشته باشید که تمام قطع کدهای که در این مقاله اورده شد در فایلی به نام support.proto قرار گرفته است، امیدوارم این مقاله برایتان مفید باشد.

۲۲ مهر، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفهوم SSH Tunneling / Port Forwarding در شبکه نوشت.

در این مقاله قصد دارم شما را با مفهومی بسیار جذاب به نام SSH Tunneling / Port Forwarding آشنا کنم، افرادی که کار System Admin در یک شرکت انجام داده اند یا دروه LPIC1 , LPIC2 را گذرانده اند حتما با این مفهوم آشنا هستن ولی در این مقاله میخواهم به صورت کامل تر و با سناریو به شرح آن بپردازم.

افرادی که علاقه مند به مباحث شبکه هستن حتما برای آنها این مقاله جذاب می باشد و این را هم بگویم که این مقاله برای کسانی مفید می باشد که حداقل دوره های network+ , CCNA یا دوره های LPIC گذرانده باشن از این جهت میگویم که اگر با این مفاهیم آشنا باشید درک عمیق تری نسبت به موضوعی که میخواهم توضیح بدهم دارید.

ولی من تا میتونم هر موضوعی که در این مقاله بحث میشه رو یک تعریف ازش داشته باشم تا دوستانی که حتی آشنایی ندارن از آن درکی پیدا کنن.

SSH Tunneling / Port Forwarding چیست ؟

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

قبل از شروع درک مفهوم SSH Tunneling باید در مورد مفهوم استاندارد SSH اطلاع داشته باشیم، SSH استانداردی برای ورودی های داده به صورت ایمن از راه دور می باشد. همچین می توان ایمن سازی ترافیک داده های هر برنامه کاربردی را با استفاده از port forwarding فراهم کرد و اساساً هر پورت TCP/IP را بر روی SSH می توان تونل کرد. به بیان ساده تر هنگامی که اتصالی را از طریق SSH برقرار می کنیم تمام داده های که بین سرور و کلاینت رد و بدل می شود به صورت رمزنگاری شده است و نمیتوان اصطلاحا ترافیک شبکه را شنود (sniff network traffic) کرد.

همانطور که در بالا مشاهده می کنید یک تونل بین یک کلاینت و سرور ایجاد شده است که از طریق SSH این تونل رمزنگاری شده است.

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

اولین مفهومی که میخواهم بگویم NAT Server می باشد، اول بگویم که چرا از این مفهوم استفاده می کنیم همانطور که در تصویر بالا مشاهده می کنید ما چند کلاینت و یک روتر و یک سرور NAT داریم که از طریق آن به اینترنت وصل شده ایم. هنگامی که ما شروع به طراحی شبکه میکنیم تمام IP های ما مثل تمام سیستم های یک دانشگاه در داخل یک شبکه Local قرار دارند. IP ها به دو دسته Public , Private تقسیم بندی می شوند، IP Private همان های هستن که به روتر ها یا سیستم های شبکه داخلی خود میدهیم و از بیرون قابل دسترس نیستن.

IP Public، این دسته از IP ها از طریق شرکت های ISP (Internet Service Provider) قابل خریدن هستن و در بستر اینترنت معتبر می باشند بدین معنی این IP در فضای ابری که آن را اینترنت می نامیم قابل دسترس هستن، پس برای اینکه ما بتوانیم به فضای اینترنت دسترسی داشته باشیم باید یک IP Valid داشته باشیم.

NAT (Network Address Translation) خب در اینجا هست که NAT وارد عمل می شود، اگر ما از NAT استفاده نکنیم و بخواهیم به اینترنت دسترسی پیدا کنیم باید برای هر سیستم یک IP Valid خریدار کنیم پس خیلی جالب نیست ! همانطور که از اسم این مفهوم پیدا می باشد وظیفه ترجمه آدرس شبکه را عهده دارد، در شکل بالا همانطور که مشاهده می کنید هنگامی که یک شبکه داخلی می خواهد به اینترنت وصل بشود در سر راه آن یک NAT Server قرار دارد که روی آن یک IP Valid تنظیم شده است . NAT Server درون IP Table خود درخواست کلاینت را از طریق IP Valid به اینترنت ارجاع می دهد بعد از اتمام و گرفتن پاسخ به IP خود آن سیستم پاسخ را برمیگرداند، پس وظیفه تبدیل و ترجمه IP ها بر عهده NAT می باشد.

هنگامی که شما بر روی سیستم خانگی خود اینترنت را از طریق هر ISP راه اندازی میکنید به شما یک IP Valid می دهد که بر روی مودم خانگی شما تنظیم شده است و از طریق NAT Server هنگامی که سایتی باز میکنید درخواست شما به فضای ابری هدایت میکند.

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

SSH Port Forwarding

خب حالا بیایم برسی کنیم و ببنیم اصلا داستان چی هست و SSH Tunneling / Port Forwarding کجا ها برای ما کاربرد داره .

: مشکل همانطور که قبلا گفتم وقتی شروع به طراحی شبکه می کنید شما در داخل یک شبکه محلی Local قرار دارید، شما وقتی که می خواهید با سرور به صورت راه دور ارتباط برقرار کنید باید به آن SSH یا telnet بزنید، خب ارتباط شما با محیط بیرون برقرار است ولی فرض کنید نیاز دارین از یک محیط دیگ مثل دانشگاه یا محیط کار به سیستم خود در خانه وصل بشوید و یک سری کار ها را انجام بدهید. در همان سناریو بالا فک کنید از بیرون میخواهید به سیستم های داخل شبکه محلی خود وصل شوید به دلیل اینکه مشکلی پیش آمده است.

خب اینجا هست که مفهوم SSH Port Forwarding وارد عمل می شود شما به راحتی می توانید یک Port بر روی یک از سیستم های داخلی خود Forward کنید به این عمل می گویند SSH Port Forwarding که از طریق آن میتوانید یک تونل امن جوری که کسی متوجه نشود ایجاد کنید. اگر هنوز ابهام دارید نگران نباشید در جلو تر به صورت کامل این مفهوم را باز میکنم.

قبل شرع میخوام به شکل های زیر دقت کنید که خیلی مهم می باشد چون برای تونل زدن خیلی راه های معتدی وجود دارد و من چهارتا از پرکاربرد ترینشو براتون آوردم :

۱. Local port forwarding - اتصال یک سرور گیرنده SSH از طریق Port Forwarding به یک سرور مقصد، من تصویر اول و دستوری که زده شده براتون بازش میکنم .

ssh -L 123:localhost:456 remotehost

: شرح دستور بالا ssh کن به صورت لوکال به پورت 123، وصل کن به localhost:456 بعد از اینکه به remotehost وصل شدی. از طریق این مفهوم ما تنوسیم یک پورتی از طریق تونل زدن وصل کنیم به یک جای دیگ پس هر موقع من وصل بشم به پورت 456 در واقع از طریق تونل به پورت 123 وصل شدیم. (-L به مفهوم Local می باشد)

۲. Remote port forwarding - خب در مفهوم قبلی یک پورت از روی کلاینت فورواد کردیم به یک لوکال هاست دیگ حالا همین تونل را میخوایم به صورت بالعکس انجام بدیم.

ssh -R 123:localhost:456 remotehost

: شرح دستور بالا وصل کن به صورت Remote / Reverse پورت 123 به localhost:456 بعد از اینکه به remotehost وصل شدی، پس اگرم من وصل بشم به پورت 123 انگار از طریق SSH Tunnel وصل شدم به پورت 456. (-R به مفهوم Remote / Reverse می باشد)

: سناریو اول فرض کنید در یک شرکتی کار میکنید به عنوان System Admin به شما یک سرور داده اند و شما را مجاب کرده اند حتما هر مشکلی پیش آمد باید بیاین اینجا و مشکل رو حل کنی و تمام دسترسی های این سرور هم از بیرون بسته است، میخوام در قالب همین مثال بحث SSH Port Forwarding بگم و هم یک راه میانبر بهتون یاد بدم که از انجامش کلی لذت ببرید.

: راه حل سناریو اول خیلی ساده شما میتوانید یک سرور VPS برای خود خریداری کنید و از طریق مفهومی که برای شما توضیح دادم یک SSH Tunnel از طریق سرور خود به سرور داخل شرکت بزنید در صورتی که هیچ کس متوجه این قضیه نشود (:

وقتی شما اتصال تونل خود را برقرار کنید هر موقع وارد یک پورت مثل 456 شدیم در واقعا وارد سرور خود روی پورتی که تنظیم کرده ایم شده ایم، من در تصویر زیر سناریوی برای شما کشیده ام، خوب توجه کنید :

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

سناریو دوم : فرض کنید شما دو سرور دارید، یک سرور به نام canada-server در کانادا می باشد و سررور dev-server در محل کار شما است که میخوایم از طریق سرور که توی کانادا داریم وصل بشیم به لبتابی که توی خونه داریم، طبق صحبت های که کردیم امکانش نباید باشه چون ما از بیرون بخوایم وصل بشیم به کامپیوتر خودمون چون داخل یک شبکه محلی هستیم امکان پذیر نیست پس راه کار چیه ؟

خب طبق شکل زیر سناریو براتو باز میکنم و راه حل و براتون توضیح میدم :

طبق صحبتی که کردیم و Tunnel که بین سیستم ما و سرور dev-server ایجاد شد خیلی راحت میتونیم با SSH کردن روی سرور داخل کانادا و از روی اون با SSH کردن به پورت 1002به سیستم داخل خونه وصل بشیم.

جمع بندی

SSH Tunneling / Port Forwarding بحث پیشرفته ای می باشد و قطعا نیاز به تجربه و گرفتن مدارک مختلفی دارد، ولی من سعی کردم سناریو محور با مفاهیم مهم شبکه اشناتون کنم و در کنارش این مفهوم خیلی جذاب و براتون شرح بدم، بسیار سناریوهای مختلفی میشه نوشت تا Tunnel های تو در توی در شبکه های خودتون ایجاد کنید، امیدوارم از این بحث در جهت مثبت استفاده کنید و به فکر هک کردن نیفتین، بحث هک و امنیت هم اگرچه در مسیر قانون مند خودش خیلی جذاب است، امیدوارم این مقاله برای دوستانی که دنبال مباحث شبکه هستن مفید باشه.

۱۷ مهر، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفهوم SQL Joins نوشت.

مقدمه

در این مقاله قصد دارم تمام حالت های که جداول شما در بین آنها پیوند به وجود می آید را از طریق مفهومی به نام SQL Joins توضیح دهم. حتما در طراحی دیتابیس به این قضیه برخورده اید که در بین جداول شما روابطی از طریق شناسه ها برقرار می شود، خب در اینجا هر جدول ممکن است به تنهایی اطلاعاتش کامل نباشد و بخواهد با Join شدن با جداول دیگر اطلاعات خود را کامل کند. خب من در این مقاله قصد دارم تمام حالت های که برای پیوند خوردن بین جداول شما به وجود می آید را به صورت کامل شرح دهم.

تذکر: این مقاله برای کسانی مفید می باشد که با یکی از دیتابیس ها مثل SQL Server آشنا باشند و مفاهیم اولیه و نوشتن Query را تا حد قابل قبولی بداند.

انواع SQL Joins

1. Inner Join

2. Left Join

3. Right Join

4. Full Outer Join

5. Left Outer Join

6. Right Outer Join

در این مقاله حتما با من همراه باشید که مطالب مفید و خوبی به دست خواهید آورد، خب قبل از شروع مباحث بالا اول خود کلمه Join را برسی کنیم. یک Join توی دیتابیس‌های رابطه‌ای، ستون‌های یک یا چند جدول رو با هم ترکیب میکنه. توی دیتابیس‌های رابطه‌ای جدول‌های مختلف با هم ارتباط هستن. حالا برای این ترکیب حالت های مختلفی به وجود می آید که هر کدوم را به صورت جدا برسی می کنیم.

در تمام مثال های بالا ما دو جدول Users و Logs را مبنا قرار می دهیم که از طریق آنها شروع به نوشتن Query می کنیم و اطلاعات داخل آنها در دو تصویر زیر تا اخر مقال مبنا می باشد.

Table Users

Table Logs

Inner Join

هنگامی که روی دو جدول Inner Join میزنیم اطلاعاتی در خروجی به ما برگرداننده می شود که باهم دیگر اشتراک دارند به عنوان مثال شما در ریاضی هنگامی که دو مجموعه ای A={5,3,6,8,4} , B={1,2,5,6,3} را دارید اشتراک آنها می شود C={5,3,6}.

الگوی استفاده از این مفهوم به صورت زیر می باشد :

SELECT [columns]
FROM `table_1`
INNER JOIN `table_2` ON [join_condition]

نکته: اگر در جایی دیدید که کلمه INNER در دستور SQL بالا وجود ندارد و فقط JOIN استفاده شده است آن هم در واقع کار همان INNER JOIN را انجام میدهد تفاوتی ندارد.

حال می خواهیم برای دو جدول users , logs مثالی بزنیم، همانطور که از اسم جداول پیدا است جدول users مشخصات کاربر را نگه میدارد و جدول logs یکسری گزارشات مربوط به فعالیت کاربر را نگه میدارد از قبیل (ورود، خروج، ثبت مقاله و غیره ..).

به عنوان مثال میخواهیم دو جدول users , logs و باهم Inner Join کنیم و ببنیم اشتراک آنها در خروجی به چه شکل می شود به دستور زیر دقت کنید :

SELECT users.name, logs.titile FROM users INNER JOIN logs ON users.id = logs.user_id;

با توجه به کوئری بالا اشتراک دو تا جدول بر اساس ستون‌های id و user_id، خروجی به صورت زیر خواهد بود :‌

به همین سادگی دیدید که ما توانستیم از طریق این مفهوم دو جدول را باهم ترکیب کنیم و هر کجا که شناسه مشترک وجود دارد نمایش دهیم، اگر به جدول اطلاعات مراجع کنید فقط 5=id=2 , id در جدول users برنگشت چون وجه اشتراکی در جدول logs ندارد و user_id در آن نیامده است.

Left Join

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

همانطور که مشاهده می کنید جدول A به همراه اشتراکش با جدول B توی قسمت آبی رنگ قرار گرفته است.

شکل دستور به صورت زیر می باشد :‌

SELECT [columns]
FROM `table_1`
LEFT JOIN `table_2`
ON [join_condition]

نکته: توی کوئری بالا، جدول سمت چپ table_1 هست که بعد از FROM اومده و جدول سمت راست table_2 هست که بعد از LEFT JOIN امده است.

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

SELECT users.name, logs.titile FROM users LEFT JOIN logs ON users.id = logs.user_id;

همانطور که در خروجی بالا مشاهده می کنید تمام دیتاها نمایش داده می شود، حتی اون های که در جدول logs وجه مشترکی هم نداشتن برگشتن ولی ستون title مقدار null گرفته اند.

Right Join

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

همانطور که مشاهده می کنید جدول B به همراه اشتراکش با جدول A توی قسمت آبی رنگ قرار گرفته است.

دستور این جوین به صورت زیر هست:

SELECT [columns]
FROM `table_1`
RIGHT JOIN `table_2`
ON [join_condition]

همانطور که قبلا گفتیم توی کوئری بالا، جدول سمت چپ table_1 هست که بعد از FROM اومده و جدول سمت راست table_2 هست که بعد از RIGHT JOIN امده است.

فرض کنید میخواهیم اطلاعات فعالیت کاربران را داشته باشیم و به این نکته توجه کنید که ممکن یک کاربر هیچ فعالیتی نداشته باشد یا حذف شده باشد، اگر از INNER JOIN استفاده کنیم فقط فعالیت مشترک برای ما نمایش میده، در این صورت همه گزارش‌ها رو بدون در نظر گرفتن موجود بودن کاربر خواهیم داشت بطوری که برای گزارش‌های بدون کاربر، خروجی null خواهد بود.

SELECT users.name, logs.titile FROM users RIGHT JOIN logs ON users.id = logs.user_id;

خب همانطور که دیدین ما سه حالت از join کردن جداول را گفتیم، بقیه حالت ها مشنق شد از همین سه حالت می باشد که من فقط به صورت شکل و مفهومی آنها را توضیح میدهم.

Full Outer Join

SELECT * FROM A FULL OUTER JOIN B ON A.KEY = B.KEY

جداول A , B را انتخاب کرده و مقادیر کلیدی جدول A و جدول B را مقایسه می کند و همه سوابق A , B را برمی گرداند و NULL را برای مقادیری که وجود ندارند در هر دو طرف پر می کند.

Left Outer Join

SELECT * FROM A LEFT OUTER JOIN B ON A.KEY = B.KEY WHERE B.KEY IS NULL

این مفهوم همان Left Join می باشد که A ، با رکوردهای منطبق در B مقایسه می شود و سمت چپ تمام مقادیرش بر میگردد و سمت راست توسط شرط join با مقادیر مشترکش چک می شود و در صورت وجود نداشتن مقدار NULL خواهد گرفت.

Right Outer Join

SELECT * FROM A RIGHT OUTER JOIN B ON A.KEY = B.KEY WHERE A.KEY IS NULL

این مفهوم همان Right Join می باشد که B ، با رکوردهای منطبق در A مقایسه می شود و سمت راست تمام مقادیرش بر میگردد و سمت چپ توسط شرط join با مقادیر مشترکش چک می شود و در صورت وجود نداشتن مقدار NULL خواهد گرفت.

جمع بندی

در این مقاله قصد داشتم حالت های join که در بین جداول شما به وجود می آید را شرح دهم تا بتوانید این مفهوم کاربردی را در پروژه های خود بکار گیرید، حتما مباحث مربوط به Query های دیتابیس را یاد بگیرد چونکه جایگاه شغلی خوبی دارد و حتما در طراحی پروژه های شما خیلی کمک میکند، من در اینجا فایلی رو لینک میکنم (Sample Command SQL) که بیشتر الگو های کاربردی کار با دستورات SQL را به صورت Template قرار داده ام تا بتوانید از آنها الگو بگیرید، امیدوارم این مقاله برای شما مفید باشد.

۸ مهر، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفهوم ACID در دیتابیس نوشت.

مقدمه

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

ACID چیست و چه کاربردی دارد ؟

در پایگاه داده، تراکنش (transaction) یک عمل واحد می باشد که به محتوای پایگاه داده دسترسی دارد (منظور از تراکنش همان عملیات خواندن، نوشتن، بروزرسانی، حذف می باشد) و سپس میتواند داده ها را به صورت بالقوه تغییر دهد. تا اینجا با مفهوم transaction در دیتابیس اشنا شدیم حالا وقت آن است که مفهوم ACID باز کنیم، هر کلمه در این مفهوم به معنای (Atomicity, Consistency, Isolation, Durability) می باشد که وظیفه این خصوصیات اطمینان از حفظ ثبات حین تعاملات روی پایگاه داده اعمال می شود.خب حالا به سراغ این بریم که این چهار مفهوم را به صورت جدا برسی کنیم.

Atomicity (اتمی بودن)

atomicity این اطمینان را به ما می دهد که یک تراکنش باید کامل انجام شود به این معنی که یک transaction از ابتدا تا انتها باید به طور کامل انجام شود و اگر در این فرایند یکی از عملیات ها به درستی انجام نشد نباید تغییرات منعکس شود.

به عنوان مثال شما فرض کنید که میخواهید یک مبلغی را از حساب جاری خود (A) به حساب پس انداز خود (B) واریزی کنید. مبالغ به ترتیب در حساب A=10000 , B=5000 و مبلع انتقال 1000 می باشد.

Read(A)
A = A - 1000
Write(A)
Read(B)
B = B + 1000
Write(B)

به صورت کلی اگر یک فرایند در ابتدا موفق بود باید در پایان هم همانطور باشد و اگر نبود بلعکس، میبنید که ما به ترتیب تمام فرانید انتقال را نوشتیم حالا شما فرض کنید در مرحله ۳ با شکست مواجه شدیم و عملیات کسر شدن از حساب A انجام شده است و باقی مانده به حساب B منتقل نمی شود، در اینجام مفهوم atomicity خود را نمایان می کند که می گوید اگر در یک فرایند ناسازگاری به وجود آمد و تا کامل شدن فرانید در بین راه شکست خورد باید تغییرات منعکس شود و تمام تغییرات به اخرین تغییرات صحیح خود برگردند.

Consistency (ثبات)

همانطور که از معنی این مفهوم پیدا است باید تمام داده ها ثبات داشته باشند یعنی در طی یک فرایند داده ها نباید از بین بروند یا به وجود بیایند. بیایم به همان مثال انتقال بانکی برگردیم و فرض کنید از دو حساب A , B باید مبلغی را به صندق بانک انتقال بدهیم به شکل زیر توجه کنید :

همانطور که مشاهده می کنید از حساب A مبلغ 100 تومان و حساب B مبلغ 200 تومان کسر شده است و جمعا باید مبلغ 300 تومان به صندق واریز شود حال زمانی مشکل رخ میدهد که در بین فرانید به هر دلیلی مثل رفتن برق سیستم قطع شود و مبالغ از حساب ها کسر شده باشد ولی به صندق انتقال پیدا نکرده باشد اینجا است که مفهوم consistency وارد عمل می شود و ثبات از بین نرفتن داده ها را تضمین میکند، پس این مفهوم خیلی حائز اهمیت می باشد.

Isolation (ایزوله)

این مفهوم به ما این تضمین را می دهد که تمام تراکنش ها به صورت جداگانه اتفاق بیفتند. ما در پایگاه داده بیشتر اوقات تراکنش های داریم که به صورت همزمان و باهم دیگر اتفاق می افتند. این فرایند باید به گونه ای باشد که هر تراکنش در یک محیط ایزوله بدون تاثیر گذاشتن بر روی دیگری اتفاق بیفتد به عنوان مثال اگر تراکنش A اتفاق بیفتد و در کنار آن تراکنش B رخ بدهد نباید هیچ تداخلی باهم دیگر داشته باشند.

Durability (پایداری)

این مفهوم همانطور که از معنی آن پیدا است در فرانید یک تراکنش این تضمین را به ما میدهد داده ها در حالت پایدار و ایمن باقی بمانند به این معنا هنگامی که یک تراکنش به پایان می رسید داده های پایگاه داده دیگر بطور دايمی ثبت شده اند و هرگز به دلیل غیر منطقی یا غیر معمول مثل رفتن برق یا خرابی سیستم از بین نمی روند.

جمع بندی

همه پایگاه داده های رابطه ای از قبیل MySQL, PostgresSQL و غیره این اصول ACID را دنبال می کنند و پایگاه داده های NoSQL بر روی دسترسی بالا تمرکز دارند، به این مفهوم است که ویژگی های consistency یا durability قربانی خود می کنند. قبل از شروع و یادگیری پایگاه داده و مفاهیم دیگر آن چه بهتر است که این مفاهیم را بدانید و نقط شروع یادگیری شما باشد، امیدوارم این مقاله برای شما مفید باشد.

۴ مهر، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفاهیم و سوالات مهمی که در لاراول باید بدانیم بخش دوم نوشت.

مقدمه

در بخش اول مقاله یک سری مفاهیم و مسائل که در لاراول به کار رفته است را بیان کردیم، حال قصد داریم به صورت کامل و کاربردی تر مسائل مهمی را در بخش دوم مقاله برایتان بیان کنم که میتواند کمک بسیاری خوبی به شما بکند، لطفا تا انتهای مقاله حتما پیش بروید که مطالب مفیدی دستگیرتان خواهد شد.

۱۵- ماکرو (macro) چیست و چه کاربردی دارد ؟

ما توسط ماکرو ها میتواینم از طریق یک کلاس داخلی در لاراول مثل Request و Response یک متد دلخواه را در آن اضافه کنیم و توسعه دهیم. این عمل اضافه کردن در هنگام اجرای اپ به صورت Run-Time رخ می دهد. با ماکرو، کلاس‌هایی رو میشه توسعه داد که از یک Trait به اسم Macroable استفاده می‌کنن برای مثال به کد زیر دقت کنید :

نمونه اول :

Request::macro('sayHello', function($argument) {
    return 'Hello';
});

نمونه دوم :

use Illuminate\Support\Collection;
use Illuminate\Support\Str;

Collection::macro('toUpper', function () {
    return $this->map(function ($value) {
        return Str::upper($value);
    });
});

با تعریف قطع کد بالا به همین راحتی می توانید یک ماکرو برای خود تعریف کنید ولی فقط نکته اینجاس که باید درون متد boot در داخل service provider آن را تعریف کنید. حالا به شکل زیر میتوانید آن را فراخوانی کنید :

$collection = collect(['first', 'second']);

$upper = $collection->toUpper();

----------------------------------------------------------------------

echo Request::sayHello(); // Hello

۱۶- Eager Loading چیست ؟

من در دو بخش مشکل و راه حل مفهوم Eager Loading را توضیح میدهم که خوب متوجه شوید چرا از این روش استفاده می شود.

خب مشکل چیست ؟ این تکنیک برای حل کردن مشکل N + 1 ساخته شده، شما فرض کنید که ما در داخل دیتابیس دوتا موجودیت به نام های books و authors داریم خب بین آنها یک رابطه به وجود آمده است که هر نویسنده کتابی دارد و هر کتاب متعلق به یک نویسنده می باشد، خب مشکل اینجاس که وقتی ما میخواهیم به عنوان مثال کوئری بنویسم که کتاب های که متعلق به نویسنده های مختلف است را برایمان بیاورد، به کد زیر دقت کنید :

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo(Author::class);
    }
}

خب حالا با قطع کد زیر تمام کتاب ها را بر میگردانیم :‌

use App\Models\Book;

$books = Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}

همانطور که در بالا گفتیم کوئری ما N کتاب را برگرداند، ولی باعث به وجود امدن مشکل N+1 شده، به زبان ساده تر برای لود کردن کتاب های هر نویسنده باید یک کوئری جدا بزند خروجی به شکل زیر می شود :

select * from books where author_id = 1
select * from books where author_id = 2
select * from books where author_id = 3
select * from books where author_id = 4

خب راه حل چیست ؟ با Eager Loading می‌تونیم به جای N + 1 کوئری، فقط ۲ تا کوئری داشته باشیم. یک کوئری برای خواندن کاربرها و یک کوئری برای خواندن کتابشون، این تکنیک توسط متدهای with و load توی لاراول قابل اجرا هست به کد زیر دقت کنید :‌

$authors = Author::all()->load('book');

foreach ($authors as $author) {
    echo $author->book->name;
}

خروجی کد SQL به شکل زیر می شود:

select * from authors
...
select * from books where author_id in (1, 2, 3, 4)

نکته آخر اینکه فرق بین متد with و load را هم برایتان بگویم،هر دو متد برای پیاده‌سازی تکنیک Eager Loading معرفی شدن هنگامی که میخواین به صورت پیوسته (کوئری دوم بلافاصله بعد از کوئری اول زده میشه) کوئری شما اجرا شود از متد with استفاده کنید به مثال زیر دقت کنید :

$users = Author::with('book')->get();

ولی هنگامی که میخواهید یک عملیاتی را انجام دهید و بعد از اجرای کوئری اول،کوئری دوم را در مکان و زمان دیگر اجرا کنید از متد load می توانید استفاده کنید که به اون Lazy Eager Loading هم گفته میشه، به کد زیر دقت کنید :

$authors = Author::all();

// Somewhere in the app
if ($condition) {
    $authors->load('books');
}

۱۷- کاربرد Route Model Binding چیست ؟

در لاراول حتما بارها با این مفهوم برخورد کرده اید که در متدی یا constructor های درون کلاس یک مدلی پاس داده شده است.به عنوان مثال در روت های که تعریف می کنید حتما شده است که $id یک کاربر را پاس داده اید ولی در قسمت ورودی تابع به شما مدلی از User بر می گردد :

Route::get('user/{id}', '[email protected]');

متدی هم که در این کنترلر وجود دارد به نام show به شکل زیر است :

public function show($id)
{
    $user = User::findOrFail($id);

    dd($user);
}

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

شکل Bind شده مدل مورد نظر به این صورت تغییر می کند :‌

public function show(User $user)
{    
    dd($user);
}

۱۸- Throttle چیست و چطوری اون رو فعال کنیم؟

Throttle یا به اون Rate Limit هم گفته می شود که با آن میتوانیم تعیین کنیم در یک بازه زمانی مشخص چه تعداد درخوست مجاز است به سمت برنامه بیاید.

مثلاً یک فرم داریم و کاربر باید بتونه توی 1 دقیقه فقط ۱۰ بار این فرم رو ثبت کنه و اگه بیشتر از ۱۰ بار شد، باید با خطای HTTP 429 (Too Many Requests) مواجه بشه. یعنی تعداد بیشتر از حد درخواست توی یک بازه زمانی.

برای همین منظور لاراول یک میدل ور برای ما اماده کرده است به نام Throttle که می توانیم روی روت های که میخواهیم تنظیم کنیم به این صورت :

Route::post('login', 'َ[email protected]')->middleware('throttle:20,1');

۱۹- روت Resource و Named چیست و چه کاربردی دارد ؟

هنگامی روت ها درون برنامه ما ایجاد می شوند ممکن است تعدادشان خیلی زیاد شود و اگر بخواهیم از آنها برای مسیردهی های داخل برنامه ی خودت استفاده کنیم یادآوری و به کار بردن آنها نسبتا سخت میشه و همچنین ممکن بعدا عوض بشوند، برای همین مفهوم Named به ما کمک می کند تا برای روت های خود یک اسم کوتاه و مختصر بگذاریم به کد زیر دقت کنید :

Route::get('/posts/laravel-project-10221/nz7eX', '...')->name('post');

حالا بجای نوشتن همچین ادرس سختی کافی است فقط نام آن را صدا بزنیم در صفحه های html خود به شکل زیر :

<form action="{{'{{'}} route('post') }}"></form>

خب مفهومی بعدی که میخواهیم در مورد آن صحبت کنیم Resource می باشد خیلی موقع ها شما یک عملیات تکرای مثل CRUD را در نوشتن روت های خود دارید یک روش این است که هر دفع بیاید برای یک موجودیت یا مدل هر چهار عمل را تکرار کنید به شکل زیر :

Route::get('books', '[email protected]');
Route::get('books/{book}', '[email protected]');
Route::post('books', '[email protected]');
Route::patch('books/{book}', '[email protected]');
Route::delete('books/{book}', '[email protected]');

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

php artisan make:controller BookController --resource

در بخش روت ها به جای تمام آنها کد زیر را داریم :

Route::resource('books', 'BookController');

۲۰- ACL چیست و روش استفاده از آن چگونه است ؟

یکی از بخش های مهم و پرکاربرد می باشد پس خوب توجه کنید، فرض کنید که ما یک فروشگاه اینترنتی داریم که از بخش های مثل مشتریان، محصولات، بلاگ، نظرات تشکیل شده است، خب ما قصد داریم برای کسانی که قرار است با اپ و یا سایت ما کار کنند محدودیت و سیاست گذاری های خاصی بگذاریم، به عنوان مثال میخواهیم بعضی از کاربرها فقط دسترسی بخش نظرات و خواندن آن ها داشته باشند و بعضی ها بتوانن گزارش گیری های مالی را انجام دهند و مثال های از این قبیل که بتوانیم سطوح دسترسی مختلفی داشته باشیم، خب برای اینکار مفهومی به نام ACL مخفف Access-control list وجود دارد که میتوانیم بدون دستکاری در جداول بی‌نهایت مجوز و نقش تعریف کنیم.

خب این مفهوم شامل چندین بخش می شود که من تک به تک آنها را توضیح میدهم :

Gate چیست ؟

همانطور که گفتیم میخواهیم فعالیت کاربر را قبل انجام عملی یا دیدن صفحه ای با تعیین سطوح دسترسی محدود کنیم به این معنی که آیا یک کاربر مجوز انجام یک کار خاص رو داره یا نه، که از کلاس (فساد) Gate استفاده و آن را عبور می دهیم.

بعنوان مثال میخواهیم برسی کنیم که در صورتی که یک کاربر نقش نویسنده را دارد بتواند پست ایجاد کند :

Gate::define('create-post', function ($user) {
    return $user->isAuthor;
});

به صورت زیر استفاده می شود :

if (Gate::allows('create-post')) {
    // The current user can create posts
}

فقط اینجا یک نکته ای مهم است که ما برای تعریف انواع سطح دسترسی باید دوتا کار انجام دهیم اگر میخواهیم به صورت Gate::define‍ آن را استفاده کنیم باید آن را توی متد boot توی فایل AuthServiceProvider تعریف کنیم.

یا اینکه باید برای مدل های که در برنامه خود داریم از طریق دستور زیر Policy تعریف کنیم :

php artisan make:policy PostPolicy -m Post

هنگامی که قطع کد بالا را اجرا میکنیم از طریق Command Line درون پوشه app یک پوشه ساخته ای می شود به نام Policies که تمام Policy های ما آنجا وجود دارد فقط آخرین کاری که باید انجام شود این است که آن را در داخل AuthServiceProvider معرفی کنیم به این صورت :

protected $policies = [
        Post::class => PostPolicy::class
];

در اخر من فقط نمونه های استفاده از این مفهوم رو به عنوان sample code میزارم تا ازش الگو بگیرید و بدانید در لاراول برای انجام یک کار راه های متعددی وجود دارد.

// ACL (Access Control List)

// if($post->owner_id !== auth()->user()->id) {
//     abort(403);
// }

// abort_if( $post->owner_id !== auth()->user()->id , 403);

// abort_unless(auth()->user()->owns($post) ,403);

// $this->authorize('view' , $post);

// if(\Gate::denies('view' , $post)){
//     abort(403);
// }

// abort_unless(\Gate::allows('view' , $post) , 403);

// auth()->user()->can('view' , $post);

۲۱- گارد (Guard) چیست؟

برای اینکه بخوایم تعیین کنیم که احرازهویت از طریق چه دستورالعملی صورت بگیره از گارد استفاده می کنیم، بعنوان مثال می خواهیم مشخص کنیم که احرازهویت از طریق رشته ای از Token صورت بگیره یا از طریق Session یا Cookie .

در لاراول ما به صورت کلی دو نوع گارد به نام های web و api داریم که web به صورت پیش فرض در لاراول استفاده می شود که تعیین می کند احرازهویت از طریق Session یا Cookie صورت بگیرد و api برای رشته ای از Token می باشد .

در قطع کد زیر می توانید مشاهده کنید که به چه صورت گارد مورد استفاده قرار گرفته :

$user = Auth::user();
$user = Auth::guard('api')->user();
$user = Auth::guard('web')->user();

خب اول از گارد پیش فرض خود لاراول استفاده کردیم برای خواندن اطلاعات کاربر در خط دوم و سوم از گارد api و web به صورت صریح استفاده کردیم تا اطلاعات کاربر را بخوانیم.

توی فایل config/auth.php می‌تونیم گاردها رو ببینیم و همچنین گاردهای دلخواهمون رو تعریف کنیم.

۲۲- فِساد (Facade) چیست؟

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

خب همانطور که قبلا اشاره کردیم سرویس ها (کلاس) مثل Session و DB و Cookie درون Service Container ثبت شده اند، خب حالا برای دسترسی راحت به سرویس ها Service Container از مفهومی به نام Facade استفاده می کنیم. فساد، یک کلاس (رابط) برای دسترسی به این سرویس‌ها بصورت استاتیک هست به عنوان مثال برای دسترسی به کلاس DB به این صورت عمل می کنیم :

$users = DB::select('select * from users where active = ?', [1]);

۲۳- صف (Queue) چه کاربردی دارد ؟

فرض کنید عملیاتی داریم که زمان اجرای آن طولانی می باشد، به عنوان مثال ارسال ایمیل به صورت انبوه بین تمام کاربران سایت، خب اگر بخواهیم این عمل را به صورت همزمان انجام دهیم و همان لحظه تمام پردازش صورت بگیرید تمام کاربران برای مدتی باید منتظر پاسخ از سرور باشند و انباشته شدن این همه درخواست به سرور هم فشار زیادی می آورد که ممکن است باعث اختلاس در سرور شود.

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

۲۴- seeder چیست ؟

حتما به این موضوع بر خورده اید که در هنگام توسعه یک برنامه نیاز دارید که دیتای Fake ایجاد کنید و روی آنها عملیات های مختلفی را انجام دهید خب در اینجا مفهومی به نام seeder کمک ما می آید که از طریق Factory می توانیم به راحتی برای هر چندتا دیتای Fake از آن استفاده کنیم.

من به عنوان مثال یک بار فرایند ایجاد کردن آن را می گویم :

php artisan make:factory UserTable

خروجی این دستور به صورت زیر می باشد و کلاسی با نامFaker به آن bind شده است که میتوانید با یک سرچ ساده استفاده از دیتای آن را متوجه شوید :

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\User;
use Faker\Generator as Faker;

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
    ];
});

بعد باید برای این Factory یک Seeder درست کنیم تا آن را با تعداد دفعات دلخواه ما فراخوانی کند :

php artisan make:seeder UsersTableSeeder

خروجی آن به این صورت می باشد :

<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(App\User::class, 10)->create();
    }
}

حالا فقط کافی است در فایلی به نام DatabaseSeeder که در مسیر database/seeds/ وجود دارد آن را فراخوانی کنیم به صورت زیر :

<?php

use App\Profile;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
    }
}

در آخر فقط کافی است دستور زیر اجرا کنیم :

php artisan db:seed

۲۵- Accessor و Mutator چیست ؟‌

اگر بخواهیم attributes های یک مدل رو طبق یک فرمت خاص نمایش دهیم یا ذخیره کنیم از این مفهوم استفاده می کنیم .

: Accessor برای زمانی که بخواهیم یک attr را به فرمت خاص نمایش دهیم به عنوان مثال یک attr را حرف اولش را به صورت Uppercase نمایش دهیم .اگه کاربرا یک Attribute به اسم name داشته باشن، اسم Accessor میشه getNameAttribute که باید اون رو بصورت یک متد توی مدل User تعریف کنیم:

<?php

namespace App\Models;

class User extends Model
{
    public function getNameAttribute($name)
    {
        return ucfirst($name);
    }
}

: Mutator فرض میکنیم که میخواهیم یک attr مقدار لخواه تنظیم کنیم به عنوان مثال میخواهیم هنگامی که password مقدار میدهیم همیشه عمل Hash شدن به صورت خودکار اتفاق بیفتد.

<?php

namespace App\Models;

class User extends Model
{
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = Hash::make($value);
    }
}

جمع بندی

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

۳۰ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفاهیم و سوالات مهمی که در لاراول باید بدانیم بخش اول نوشت.

مقدمه

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

خب در اینجا هم قصد دارم این مفاهیم رو خیلی ساده و کاربردی بیان کنم تا برای همیشه آنها را در ذهن داشته باشید و در پروژه های خود بکار بگیرید.

۱ - از لاراول چی میدونی ؟

لاراول محبوب ترین فرم ورک PHP می باشد که تحت معماری MVC بنا شده است و برای توسعه نرم افزار های تحت وب طراحی شده است، با اینکه تحت سرور نوشته شده است ولی شما میتوانید فرانت اند خود را هم از طریق ابزار های قوی که در اختیار شما می گذارد از قیبل Mix و Blade آن را مدیریت و توسعه دهید.

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

همچنین از نظر امنیت از سیستم اهراز هویت پشتیبانی می کند که کار کردن با این فرم ورک را جذاب می کند و همچنین ویژگی ها و امکانات کاربردی دیگ برای کار با دیتابیس از قبیل ORM و Eloquent و Artisan که میتوانید خط فرمان لاراول را به خوبی مدیریت کنید و خیلی از وپژگی های منحصر به فرد دیگری که کار کردن با این فرم ورک را جذاب می کند.

سه تا از ویژگی ها دیگر لاراول به نظرم باید به آنها اشاره کنم مورد اول در حال رشد (Progressive) بود آن است یعنی به طور مداوم این فرم ورک در حال تغییر می باشد و باید دانش خودتون نسب بهش بروز کنید. مورد دوم مقیاس پذیری (Scalable) خب همانطور که می دانید ما هرچه بتونیم با منابع کمتر عملکرد بالاتری داشته باشیم خیلی برای ما بصرفه تر و بهتر است خب با پشتیبانی و بروز رسانی های PHP و با فراهم ساختن امکان سیستم های کش مثل Redis ما میتوانیم میلیون ها درخواست را در ماه مدیریت کنیم.

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

۲- Laravel و Lumen چه تفاوتی باهم دیگر دارد ؟‌

همانطور که می دانید Laravel با ابزار ها و ویژگی ها متعددی برای ساخت اپلیکیشن های تحت وب نوشته شده است که میتوان به برخی از آن ها مثل سشن، روتینگ، الوکوئنت و حتی Template Engine اشاره کرد. Lumen به عنوان یک microservice شناخته می شود که خیلی از ابزار های که در بالا نام بردیم را ندارد و هدف آن سرعت و سبکی است برای همین اکثر برای طراحی API و ارتباط گرفتن سرویس ها باهم دیگر بسیار مناسب است .

۳- هر پوشه در لاراول وظیفه چه کاری را دارد‌ ؟

خب در اینجا یکبار کامل من ساختار بندی پوشه ها را به ترتیب برای شما می گوییم :‌

پوشه app

هسته اصلی لاراول که در آن تمام کتابخانه و سرویس های اجرا می شوند در این پوشه می باشد.

پوشه bootstrap

هنگام راه اندازی پروژه اولین پوشه که شروع (root) به اجرای بقیه اجزا می کند می باشد که درون خود یک فایل به نام app.php است که وظیفه راه اندازی فرم ورک را بر عهده دارد و پوشه ای به نام cache که فرم ورک فایل های را برای افزایش سرعت، تولید میکند. فایل های از قبیل تنظیمات یا روت ها و سرویس ها می باشد.

پوشه config

تمام تنظیمات و پیکربندی های لاراول از قبیل دیتابیس، کش، سشن، هش و غیره ... در این اینجا می باشد.

پوشه database

تمام فایل های مربوط به migartion ها و مدیریت کلاس Factory و Seeder در اینجا وجود دارد.

پوشه public

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

پوشه routes

به صورت پیش فرض تمام روت های که شما تعریف می کنید در این پوشه قرار دارد که شامل این فایل های می باشد web.php, api.php, channels.php, console.php می باشد پیکربندی های فایل web.php در داخل سرویس RouteServiceProvider تعریف شده اند که بعنوان مثال همه آنها از middleware به نام web گذر می کنند و برای تمام روت ها اعمال می شود.

پوشه resources

این پوشه شامل views های است که در پروژه خود تعریف می کنید همچنین تمام کد های برای css و javascript می نویسید درون این قسمت قرار دارد و بعد از کامپایل شدن به پوشه public منتقل می شود. همچین تمام زبانهای که ممکن است در اپ خود استفاده کنید در پوشه به نام lang وجود دارد.

پوشه storage

این پوشه شامل تمام logs, caches, sessions و فایل های کامپایل شده blade می باشد که توسط برنامه شما ایجاد شده.

پوشه tests

این پوشه شامل تست های است که توسط PHPUnit برای سیستم خود نوشته اید.

پوشه vendro

این پوشه شامل تمام پکیج های می باشد که توسط composer برای واسبتگی های پروژه خود نصب کرده اید.

۴ - کاربرد middleware چیست ؟

میدل‌ ورها برای فیلتر کردن درخواست های HTTP مورد استفاده قرار گرفته اند، در حفیقت middleware به عنوان یک واسط بین درخواست های کلاینت به برنامه ای شما می باشد. هنگامی که یک درخواست از سمت کاربر ارسال می شود بهتر هست قبل از اینکه به برنامه اصلی ما برسد از یک لایه میانی تحت عنوان میدل ور عبور کند تا باعث امن تر شدن برنامه ما شود.

بطور کلی میدل ورها به سه دسته تقسیم می شوند :

۱ . میدل ورهای سراسری: این مورد توی همه درخواست های به سمت برنامه اجرا می شود.

۲. میدل ورهای روت ها: این مورد فقط بر روی یک روت خاص یا گروهی از روت ها می تواند اجرا شود.

۳. میدل ور های کنترل ها: این مورد بر روی constructor کنترلر اجرا می شود.

۵- Artisan چه کاربردی دارد ‌؟

artisan یک رابط خط فرمان CLI اختصاصی لاراول می باشد که سرعت فوق العاده ای به توسعه برنامه ما می بخشد.

۶- ORM چیست ؟

ORM مخفف Object-Relational-Mapping می باشد یک مفهوم کلی می باشد، در واقع به عنوان یک لایه انتزاعی برای دستورات SQL عمل می کند که ما بدون در نظر گرفتن نوع دیتابیس می توانیم از این دستورات استفاده کنیم، به کد زیر دقت کنید‌:

DB::table('tasks')->select('title')->get();

ما بدون در نظر داشتن اینکه کوئری بالا مربوط به چه نوع دیتابیس از قبیل MySQL یا MongoDB باشد، اجرا می شود و ما هیچی دستور SQL نمی یبینیم.

۷- Eloquent چیست ؟

حالت پیاده سازی شده ORM در فرم ورک لاراول می باشد و مدل ها وظیفه ارتباط برقرار کردن با موجودیت های دیتابیس را دارند که از طریق این مفهوم دستورات پیچیده SQL خود را به راحتی اجرا کنید.

بعنوان مثال مدل User توسط ORM به موجودیت users دسترسی دارد :‌

User::find(1)

۸- Service Provider چیست ؟

لطفا به این مفهوم به خوبی توجه کنید که قدرت لاراول در این بخش می باشد، هر برنامه ای برای اینکه اجرا بشه باید چندین کلاس و فایل را لود و اجرا کند، سرویس های از قبیل سشن، کوکی، دیتابیس و ...، قبل از لود شدن باید برنامه ای ما کار اصلیش رو انجام بده، این لود شدن ها در قسمت Service Provider ها انجام می شود به صورت فنی تر این قسمت مسئول پیکربندی و آماده سازی پروژه است.

خب حالا در اینجا مفهومی وجود دارد به نام Service Container به معنی مخزن یا مکانی برای نگهداری سرویس ها (کلاس) که برنامه ما به آن نیاز دارد به بیان دیگر یک ابزار برای مدیریت و تزریق وابستگی‌ها (Dependency Injection) توی برنامه هست. سرویس‌هایی مثل Cache و Session و DB توی این مخزن نگهداری میشن.

شما هنگامی که یک Service Provider برای اپ خود ایجاد می کنید درون فایل آن دوتا متد به نام های boot و register وجود دارد و باید تفاوت آن را بدانید.

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

حالا به محضی که متد register تمام پروایدر ها رو پردازش می کند، متد boot همه پروایدر های که توسط فرم ورک لود شده اند را پردازش می کند.

از متد register برای bind کردن یک سرویس (کلاس) به صورتی که در کل پروژه بتوان آن را inject کرد استفاده می شود به عنوان مثال می خواهیم سرویس notification را هم در برنامه داشته باشیم و اون رو به کل اپ معرفی کنیم :

$this->app->bind('App\Contracts\Notification', function() {
    return new EmailNotification;
})

حال خیلی راحت می توانید در رون constructor یا یک متد دلخواه در Controller آن را inject کنید و یا بصورت مستقیم در کل برنامه استفاده کنید.

class UsersController extends Controller
{
    public function index(Notification $notification)
    {
        dd($notification); // App\Services\EmailNotification
    }
}

۹- چرا از Form Request استفاده می کنیم ؟

عملیات اعتبارسنجی (validation) همیشه ساده نیست و گاهی نیاز داریم ورودی های زیادی رو برسی کنیم، با استفاده از Form Request می توانیم انعطاف پذیری و مدیریت اعتبارسنجی را بالا ببریم.

public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

درون متد rules می توانید اعتبارسنجی فیلد های که میخواهید را انجام بدهید .

public function messages()
{
    return [
        'title.required' => 'لطفاً عنوان را وارد کنید'
    ];
}

در متد messages میتوانید پیامی که میخواهید برگرداند رو بنوسید.

۱۰- Localization چیست ؟

اگر قصد دارید یک برنامه با چندین زبان مختلف بنویسید و آن در دسترس کاربران برنامه خود قرار دهید میتوانید از مفهوم Localization در مسیر resources/lang استفاده کنید.

۱۱- نسخه بندی معنایی چیست ؟‌

هدف از نسخه بندی معنایی (Semantic Versioning)، استاندارد سازی نسخه هایی هست که یک نرم افزار نسبت داده می شود. در نسخه‌بندی معنایی، اعداد یک ورژن، شامل سه عدد هست که با نقطه از هم جدا میشن. یعنی طبق فرمت X.Y.Z که توی اونها x و y و z اعداد صحیح هستن:

X: نشون‌دهنده نسخه اصلی (Major Version) نرم‌افزار هست. Y: نشون‌دهنده نسخه جزیی (Minor Version) نرم‌افزار هست. Z: نشون‌دهنده نسخه پچ (Patch) نرم‌افزار هست.

برای مثال برای ورژن 6.12.3 یک نرم‌افزار، نسخه‌ی اصلی 6، نسخه جزیی 12 و نسخه پچ اون 3 هست.

به مفهوم دیگر X نشانه نسخه اصلی برنامه می باشد، Y هنگامی تغییر می کند که یک ویژگی جدید به برنامه اضافه شده باشد، Z به مفهوم رفع باگ ها و خطاهای احتمال برنامه می باشد.

۱۲- چطور یک متغییر سراسری داشته باشیم ؟‌

برای اینکه شما در برنامخ خود یک متغییر سراسری تعریف کنید کافی است به پوشه config بروید و بعنوان مثال یک فایل به نام settings.php ایجاد کنید که محتوای آن به شکل زیر می باشد :

// config/settings.php

<?php

return [
    'api_version' => env('API_VERSION'),
    'path' => [
        'images' => '/path/images',
    'audio' => '/path/audio',
        'videos' => '/path/videos'
    ],
    'theme' => 'dark',
];

حالا خیلی راحت می توانید از طریق متد config در هر جای برنامه که می خواهید از آن استفاده کنید :

config('settings.path.images');

۱۳- تفاوت بین Package Manager و Dependency Manager چیست ؟

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

خب یک راه اینکه که خودمون تک به تک وابستگی ها را فراهم و نصب کنیم. شرایط زمانی سخت تر می شود یک ابزار وابسته به یک ابزار دیگر باشد به همین منظور سبب شده تا ابزار های مثل Package Manager و Dependency Manager معرفی بشن.

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

Package Manager :‌ در سطح بالاتر و کلی تر فعالیت می کند، یعنی در سطح سیستم و نه برای یک برنامه خاص، ابزار های که توسط Package Manager نصب می شوند می توانند چندین برنامه از آنها استفاده کنند به عنوان مثال شما در لینوکس APT و YUM رو دارید که در سطح سیستم قابل دسترس هستن.

Dependency Manager : فقط در سطح یک نرم افزار فعالیت می کنند، یعنی وابستگی های یک برنامه توسط Dependency Manager نصب می شوند و فقط در سطح همان برنامه قابل دسترس هستند به عنوان مثال :

Composer درPHP

NPM در NodeJS

Bundle در Ruby

۱۴- Composer چیست ؟‌

کامپوزر یک ابزار مدیریت وابستگی Dependency Manager برای PHP می باشد که به ما اجازه می دهد تا ابزارهای مورد نیاز برنامه ها را مدیریت و نصب کنیم.

هر چند کامپوزر با پکیج ها سرکار دارد ولی چون در سطح یک برنامه عمل می کند Dependency Manager به حساب می آید.

جمع بندی

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

۲۹ شهریور، ۱۴۰۰

٢ سال پیش ١۰۰+ امتیاز
@reskipper به گفتگوی ارسال کد ثبت نام(عدم لاگین قبل و بعد) جواب داد.

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

ولی مشکل با یک تابع is_login که لاگین بودن کاربر و از طریق session که براش ایجاد کردین حل میشه به نظرم و هر جا که خواستین صفحه ی نمایش نده با یک if ساده میتونید مدیریتش کنید.

برای بحث verify هم اگه بار اول ریحستر میکنه و شروع به لاگین میکنه در صورت verify شدن باید فلگ verified_email به صورت true در بیاد در دیتابیس و اینو توی کویٔری مدیریت کنید و اگه دیبایس هنوز دخیل نکردین session ست کنید باز مثل همون قضیه لاگین بودن مدیریتش کنید.

۲۷ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم راهنمایی کامل روابط جداول در لاراول - بخش ۲ نوشت.

همانطور که اطلاع داشتین ما در ۲ بخش می خواستیم تمام حالت های ارتباطات جداول در لاراول را شرح دهیم، اگر احیانا بخش اول را مطالعه نکرده اید لطفا (راهمایی کامل روابط جداول در لاراول بخش ۱) روی این لینک کلیک کنید و در صورت نیاز آن را مطالعه کنید. ما در مقاله قبلی در مورد سه نوع ارتباط به نام های One To One، One To Many، Many To Many صحبت کردیم و در ادامه به مطالعه موارد در پایین ذکر شده می پردازیم :

Has One Through .4 (یک به یک واسطه ای)

Has Many Through .5 (یک به چند واسطه ای)

One To One (Polymorphic) .6 (یک به یک پلی مورفیک)

One To Many (Polymorphic) .7 (یک به چند پلی مورفیک)

Many To Many (Polymorphic) .8 (چند به چند پلی مورفیک)

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

ثبت و ویرایش

شما اگر بخواهید در جدول واسط اطلاعات را درج کنید می توانید از دو متد save() و یا attach() استفاده کنید به مثال زیر دقت کنید :

$role = App\Role::find(5);

App\User::find(1)->roles()->save($role);

// or

App\User::find(1)->roles()->attach($role);

دقت کنید آرگومانی که پاس می دهیم به متد های save() و attach() باید از نوع Model باشند. همچنین ما میتوانیم برای پاک کردن چندین نقش و نسب دادن نقش های جدید به صورت هم زمان از متدی به نام sync() استفاده کنیم به کد زیر دقت کنید :

$roles = App\Role::whereIn('id', [1, 2, 3])->get();

App\User::find(1)->roles()->sync($roles);

اگر نخواهیم نقش های قدیمی پاک شود به آرگومان دوم متد sync مقدار false می دهیم یا از متد زیر استفاده می کنیم‌ :

$user->roles()->syncWithoutDetaching([1, 2, 3]);

برای حذف کردن نقش های نسبت داده شده به یک کاربر از متد detach() استفاده می‌کنیم:

$roles = App\Role::whereIn('id', [1, 2, 3])->get();

App\User::find(1)->roles($roles)->detach();

سعی کردم تقریبا تمام مباحث مهم و کاربردی تا اینجا برای بحث های باقی مانده پوشش بدهم بریم سراغ مباحث جدید با من همراه باشید.

Has One Through (یک به یک واسطه ای)

در رابطه has-one-through همانطور که از اسمش پیدا است مدل ها از طریق یک واسطه باهم ارتباط می گیرند. خب با مثال زیر به توضیح آن می پردازیم :

users
    id - integer
    reviewer_id - integer

reviewers
    id - integer

activities
    id - integer
    user_id - integer

در اینجا به سه مدل User و Reviewer و Activity را در نظر داشته باشید که در این مثال قرار است فعالیت هر کاربر رو از طریق داوران بدست بیاریم، در اینجا دقت کنید که در جدول activites کلیدی به نام reviewer_id وجود ندارد برای همین منظور ما از ارتباط hasOneThrough استفاده می کنیم.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Reviewer extends Model
{
    /**
     * Get the reviewer's activity.
     */
    public function activity()
    {
        return $this->hasOneThrough(
            'App\Activity',
            'App\User',
            'reviewer_id', // Foreign key on users table...
            'user_id', // Foreign key on activities table...
            'id', // Local key on reviewers table...
            'id' // Local key on users table...
        );
    }
}

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

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

$reviewer = Reviewer::first();
$activity = $reviewer->activity;

Has Many Through (یک به چند واسطه ای)

در رابطه has-many-through همانطور که از اسمش پیدا است ما در این رابطه مدلی را داریم که ارتباط با چند موجودیت مدل دیگر دارد به عنوان مثال یک مدل Country ممکن است دارای بسیاری از مدل های Post از طریق یک مدل User ​​باشد خب حالا شما به راحتی میتوانید تمام پست های مربوط به یک کشور خاص را از طریق مدل User بدست بیاورید.

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string

همانطور که مشاهده می کنید ما ستون country_id را در جدول posts نداریم برای همین منظور ما دنبال رابطه هستیم که بتوانیم از طریق آن به این صورت $country->posts تمام پست های یک کشور را به دست بیاریم. برای این کار فقط کافی است در مدل Country ارتباط از طریق متد hasManyThrough برقرار کنیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    /**
     * Get all of the posts for the country.
     */
    public function posts()
    {
        return $this->hasManyThrough(
            'App\Post',
            'App\User',
            'country_id', // Foreign key on users table...
            'user_id', // Foreign key on posts table...
            'id', // Local key on countries table...
            'id' // Local key on users table...
        );
    }
}

همانطور که مشاهده می کنید ما ارتباط کشور را با مدل پست از طریق مدل کاربر برقرار کردیم حالا فقط کافی است به صورت زیر از آن استفاده کنیم :

$country = Country::find('Asia');

dump($country->posts);

Polymorphic Relationships

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

One To One (Polymorphic) (یک به یک پلی مورفیک)

رابطه one-to-one polymorphic خیلی شبیه به رابطه one-to-one می باشد، خب حالا بیایم با یک مثال اون و برسی کنیم فرض کنید شما سه مدل User و Post و Image دارید در اینجا یک وجه مشترک وجود دارد و آن این است که هم مدل User و هم مدل Post به مشخصات درون Image نیاز دارند یعنی ما به تصویر هم برای کاربران و هم برای پست ها خودمون نیاز داریم پس به همون جلمه اول بر میگردیم که گفتیم یک رابطه می تواند به مدل های مختلفی تعلق داشته باشد. به مثال زیر دقت کنید :

posts
    id - integer
    name - string

users
    id - integer
    name - string

images
    id - integer
    url - string
    imageable_id - integer
    imageable_type - string

نکته بسیار مهم که اینجا وجود دارد دوتا ستونی است که در جدول images قرار دارند به نام های imageable_id و imageable_type که هر کدام وظیفه مشخصی دارند. imageable_id در خود مقدار شناسه users یا posts رو نگه میداره و imageable_type مقدار مدلی که مربوط به اون شناسه می باشد برای ارتباط گرفتن کلاس Eloquent می باشد.

همیشه قرارداد لاراول برای دوتا فیلد imageable_id و imageable_type به این صورت است که اسم مدل مقصد + کلمه able. اینجا مدل ما Image هست که با کلمه able میشه imageable.

ساختار کلی تمام جدول ها را در زیر مشاهده کنید :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Image extends Model
{
    /**
     * Get the owning imageable model.
     */
    public function imageable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    /**
     * Get the post's image.
     */
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable');
    }
}

class User extends Model
{
    /**
     * Get the user's image.
     */
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable');
    }
}

حالا وقتش رسیده ازش استفاده کنیم به عنوان مثال بیایم تصویر مربوط به یک پست را برگردانیم، فقط کافی است از ویژگی image dynamic property که ایجاد کردیم استفاده کنیم :

$post = App\Post::find(1);

$image = $post->image;

همانطور که مشاهده کردید ما توانستیم یک رابطه یک به یک از طریق متد morphOne() ایجاد کنیم.

ثبت ویرایش و حذف

حالا خیلی راحت میتونیم سه عملیات ثبت و ویرایش و حذف بر روی اون انجام بدیم :

// Insert
App\Post::find(1)->image()->create([
    'url' => '...'
]);

// Update
App\Post::find(1)->image()->update([
    'url' => '...'
]);

// Delete
App\Post::find(1)->image()->delete();

دقت داشته باشید که مقادیر imageable_id و imageable_type به صورت خودکار پر می شود.

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

$image = App\Image::find(1);

dump($image->imageable);

مقدار ->imageable یک پراپرتی دینامیک هست که حاوی مقدار مدل مبدا است، اینجا ما با مدل های User و Post سرکار داریم و این در واقع همون اسم مدلی هست که در مدل Image است.

One To Many (Polymorphic) (یک به چند پلی مورفیک)

رابطه one-to-many polymorphic خیلی شبیه به رابطه one-to-Many می باشد بیاین با یک مثال اون برسی کنیم شما فرض کنید سه مدل Video و Post و Comment دارید حالا تصور کنید که کاربران شما میخواهند روی پست ها و ویدیو های شما کامنت بگذارند . یعنی هم مدل Post و هم Video نیاز دارن با مدل Comment ارتباط داشته باشند برای همین یک رابطه یک به چند شکل می گیرد بین آنها، ولی نکته اینجاس که ما برای هر دو مدل جالب نیست دوتا جدول comments تعریف کنیم فقط کافی است ارتباط آنها را از طریق متد morphMany برقرار کنیم به مثال زیر توجه کنید :

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

این از شکل جدول های ما و حالا بیایم سریع ارتباط مدل های اون ها رو شکل بدیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * Get the owning commentable model.
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    /**
     * Get all of the post's comments.
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

class Video extends Model
{
    /**
     * Get all of the video's comments.
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

همنطور که مشاهده می کنید مدل Comment متد commentable را برای ارتباط با مدل های دیگ تعریف می کنیم و حالا فقط کافی است که ارتباط مدل Post و Video از طریق متد morphMany که آرگومان اول مدل ارتباطی و آرگومان دوم اسم رابطه پلی‌مورفیک که commentable است تعریف و ارتباط را برقرار کنیم.

ثبت و ویرایش اطلاعات و حذف

نحوه ثبت، ویرایش و حذف اطلاعات مثل رابطه پلی‌مورفیک یک به یک هست:

// Insert
App\Post::find(1)->comments()->create([
    'body' => '...'
]);

// Update
App\Post::find(1)->comments()->find(5)->update([
    'body' => '...'
]);

// Delete
App\Post::find(1)->comments()->delete();

برای به دست اوردن اطلاعات هم از طریق کد زیر این اقدام می کنیم :‌

$post = App\Post::find(1);

foreach ($post->comments as $item) {
    echo $item->body;
}

همانطور که قبلا گفتیم برای ارتباط معکوس آن هم به این صورت عمل می کنیم :‌

$comment = App\Comment::find(1);

$commentable = $comment->commentable;

Many To Many (Polymorphic) (چند به چند پلی مورفیک)

اخرین رابطه ی که میخوام در موردش صحبت کنم Many-to-many polymorphic می باشد که نسبتا توی روابط چند به چند پیچیدگی بیشتری نسبت بع روابط دیگر وجود دارد، خب حالا دوباره با یک مثال پیش میریم شما چهار مدل Post ٰو Video و Tag رو در نظر بگیرید، پست یا یک ویدئو میتونه چند تگ داشته باشه و هر تگ میتونه متعلق به هر پست و ویدیو باشه. توی روابط چند به چند، موجودیت‌ها مستقل از هم تعریف میشن و ما فقط به یک جدول واسط برای برقراری ارتباط آن ها نیاز داریم .

posts
    id - integer
    name - string

videos
    id - integer
    name - string

tags
    id - integer
    name - string

taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string

خب همانطور که مشاهده می کنید برای هر موجودیت یک جدول جدا تعریف کردیم و موجودیت ها همگی مستقل از همدیگر هستند و جدولی که به عنوان واسط عمل می کند taggables نام دارد، قبلا در مورد taggable_id و taggable_type صحبت کردیم ولی اینجا یک ستون دیگه به نام tag_id وجود داره که ارتباط و با مدل های دیگ برقرار کنه.

حالا بیایم مدل ها رو باهم اتباط بدیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * Get all of the tags for the post.
     */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}

ارتباط مدل post را از طریق متد morphToMany مشخص می کنیم که با چندین تگ به صورت پلی‌مورفیک که taggable نام دارد در ارتباط است.

حالا فقط کافیه رابطه معکوس آن را مشخص کنیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    /**
     * Get all of the posts that are assigned this tag.
     */
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'taggable');
    }

    /**
     * Get all of the videos that are assigned this tag.
     */
    public function videos()
    {
        return $this->morphedByMany('App\Video', 'taggable');
    }
}

حالا برای بدست آوردن اطلاعات فقط کافی است به صورت زیر عمل کنیم :

$post = App\Post::find(1);

foreach ($post->tags as $tag) {
    //
}
$tag = App\Tag::find(1);

foreach ($tag->videos as $video) {
    //
}

ثبت و ویرایش اطلاعات و حذف

برای ثبت اطلاعات می‌تونیم از متد save() یا attach() استفاده کنیم:

$tag = App\Tag::find(5);

App\Post::find(1)->tags()->save($tag);

// or

App\Post::find(1)->tags()->attach($tag);

همانطور که قبلا گفتیم از متد sync() هم میتوانید استفاده کنید :

$tags = App\Tag::whereIn('id', [1, 2, 3])->get();

App\Post::find(1)->tags()->sync($tags);

جمع بندی

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

۲۵ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم راهنمایی کامل روابط جداول در لاراول - بخش ۱ نوشت.

مقدمه

همانطور که میدانید هنگامی که شروع به طراحی پایگاه داده می کنید بین جداولی که میسازید روابط مختلفی ایجاد می شود به عنوان مثال اگر شما جدولی به نام posts داشته باشید و درکنار آن جدول دیگری به نام comments باشد رابطه به این صورت تعریف می شود که هر post می تواند چندین comments داشته باشد و هر comment می تواند متعلق به یک post باشد. نوع رابطه بالا One To Many یا یک به چند می باشد، خب در این مقاله قصد دارم تمام حالت های مهمی که لاراول برای کار با Eloquent: Relationships بین روابط جداول قرارداد کرده است را باهم برسی کنیم.

انواع روابط در لاراول

  1. One To One (یک به یک)
  2. One To Many (یک به چند)
  3. Many To Many (چند به چند)
  4. Has One Through (یک به یک واسطه ای)
  5. Has Many Through (یک به چند واسطه ای)
  6. One To One (Polymorphic) (یک به یک پلی مورفیک)
  7. One To Many (Polymorphic) (یک به چند پلی مورفیک)
  8. Many To Many (Polymorphic) (چند به چند پلی مورفیک)

جداول شما از طریق مدلی به نام Eloquent که به متد های مختلفی برای روابط بین جداول شما تعریف شده است دسترسی دارد و کار شما را برای تعریف این روابط بسیار آسان کرده است. به عنوان مثال شما میتوانید با زنجیره زدن بین مدل های که تعریف کرده اید اطلاعات را به صورت های مختلف از دیتابیس واکشی کنید به مثال زیر دقت کنید :

$user->posts()->where('active', 1)->get();

قطع کد بالا به این مفهوم می باشد که تمام پست های که مربوط به یک کاربر خاص با ضعیت فعال می باشد برگرداند. خب به همین راحتی توانستید یک Query که باید زمان بیشتری را برایش صرف می کردین را از طریقی مفهومی به نام query builders به راحتی اجرا کنید.

خب حالا برویم تمام روابط را یک به یک با هم برسی کنیم.

One To One (یک به یک)

یکی از پایه ترین روابطی که بین جداول برقرار می شود رابطه ای One To One می باشد به عنوان مثال شما فرض کنید هر User دارای یک حساب یا Account می باشد. در اینجا شما با دو مفهوم hasOne و belongsTo آشنا می شوید بیاید باهم کد زیر را برسی کنیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{

    public function account()
    {
        return $this->hasOne('App\Account');
    }
}

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

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

public function account()
{
}

بدنه این تابع را از طریق مدل User و کلمه کلید $this که به خود آن اشاره دارد به تابع دسترسی پیدا کردیم که متد hasOne با اولین ورودی خود مدل Account دریافت کرده و مقداری را باز میگرداند.

 return $this->hasOne('App\Account');

همچنین توجه داشته باشید پارامتر دومی که تابع hasOne می گیرد مقدار foreign_key می باشد که از طریق آن میتوانید کلید خارجی جدول خود را تعریف کنید ولی لاراول به صورت پیش فرض آن را برای این مثال طبق قرارداد های خودش user_id در نظر می گیرید.

خب حالا بیاید ببنیم چطور میتوانید از آن استفاده کنید:

$account = User::find(1)->account;

ببنید که ما چطور بصورت زنجیره ای توانستیم اطلاعات حساب یک کاربر را طبق رابطه ای که تعریف کردیم نمایش دهیم. در واقع توابع account همان رابطه ای است که در مدل User تعریف کردیم. لاراول دسترسی به این نوع رابطه (account<-) را Dynamic properties نامیده است یعنی به صورت یک پراپرتی درون کلاس موجود است.

پس از اجرای دستور بالا خروجی SQL زیر در پس زمینه حاصل می شود :

select * from `accounts` where `accounts`.`user_id` = ? and `accounts`.`user_id` is not null limit 1

حالا همین رابطه را به صورت معکوس برای جدول Account داریم، کلمه معکوس بخاطر این است که اگر ما بخوایم چه از جدول User به جدول Account دسترسی داشته باشیم چه برعکس باید این عمل انجام شود.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Account extends Model
{
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

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

توجه داشته باشید چون مدل های ما در کنار هم دیگر هستن می توانید مقدار ورود توابع را از این حالت App\User به این حالت User::class تغییر دهید.

توابع belongsTo سه تا آرگومان را از خود عبور می دهد که به شرح زیر می باشد :

return $this->belongsTo('App\User', 'foreign_key', 'other_key');

۱. مدلی که میخواهید با آن ارتباط برقرار کنید.

۲. میتوانیم بگویم که کدام ستون accounts مد نظر ما می باشد که به صورت پیش فرض user_id را در نظر می گیرد.

۳. متیونم مشخص کنیم اگه از id استفاده نمی کنیم که کدوم ستون جدولusers مد نظر ما می باشد.به صورت پیش فرض id می باشد.

One To Many (یک به چند)

این رابطه به این معنی می باشد که ما یک مدلی به نام post داریم که با مدل دیگری مثل comment رابطه one-to-many دارد. بیاید در کد آن را برسی کنیم.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * Get the comments for the blog post.
     */
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }
}

همانطور که مشاهده می کنید در مدل Post ما یک رابطه با comments تشکیل داده ایم، همانطور که قبلا گفتم از درک مفهوم و تعریف کاری که می کنیم باید به پیاده سازی برسیم، خب حالا باید در یک جلمه آن را تعریف کنیم که به این صورت می باشد باید بگویم هر پست دارای چندین کامنت می باشد پس پیاده سازی گام به گام به این صورت می شود :

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

public function comments()
{
}

در بدنه این تابع برای ارتباط hasMany مقدار زیر تعریف میکنیم :

return $this->hasMany('App\Comment');

ما توانستیم با فرض اینکه ستون post_id در جدول comments وجود دارد ارتباط آن را برقرار کنیم، حال فرض کنید که می خواهیم کامنت های یک پست را مشاهده کنیم، به کد زیر توجه کنید :

$comments = App\Post::find(1)->comments;

foreach ($comments as $comment) {
    //
}

خب با قطع کد بالا توانستیم به تمام کامنت ها با دستور <-comments دسترسی پیدا کنیم فقط دقت کنید توی مثال بالا یک پراپرتی داینامیک به کلاس Post اضافه شد و اگر بخواهیم محدودیت در آن ایجاد کنید باید از متد comments() استفاده کنید و به شکل زیر آن را تغییر دهید.

$comment = App\Post::find(1)->comments()->where('title', 'foo')->first();

حال همانطور که در صحبت های قبل گفتیم روابط باید به صورت معکوس تعریف شوند حالت نوبت به مدل Comment رسیده است رابطه خود را با مدل Post شکل بدهد.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * Get the post that owns the comment.
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

خب همانطور که مشاهده می کنید معکوس رابطه به این صورت می باشد که هر comment متعلق به یک post است که با متد belongsTo نسبت داده می شود.

حال بیایم با قطع کد زیر یک کامنت را گرفته و پست مورد نظر او را نمایش دهیم :

$comment = App\Comment::find(1);

echo $comment->post->title;

شکل کامل متد belongsTo به شکل زیر می باشد :

    return $this->belongsTo('App\Post', 'foreign_key', 'other_key');

Many To Many (چند به چند)

اخرین بخشی که میخوام در بخش اول این مقاله بگم رابطه Many-to-many می باشد که نسبتا پیچیده تر از روابط hasOne و hasMany است، ما با فرض اینکه دوتا جدول به نام های users و roles داریم وارد این مثال می شویم . تعریف اولیه ما از رابطه چند به چند بین این جداول به معنی است که هر کاربر چندین نقش دارد و هر نقش میتواند مرتبط به چندین کاربر باشد.

بعنوان مثال هر کاربر میتواند نویسنده و مدیر باشد و برعکس آن هر نقش میتواند متعلق به چند کاربر باشد .

اول به جداول زیر توجه کنید تا کامل شرح بدهم چطور میتوانیم همچین رابطه ای شکل بدهیم :

users
    id - integer
    name - string

roles
    id - integer
    name - string

role_user
    user_id - integer
    role_id - integer

خب گام به گام من جلو میرم و خوب توجه کنید در اینجا لاراول از مفهومی به نام Alphabetical order استفاده می کند، فرایند جداول واسط با این مفهوم شکل می گیرند. وقتی ما یک رابطه چند به چند یا n به n داریم جدولی واسط به وجود می آید به نام pivot_table که قرارداد لاراول می باشد. خب در این جا جدولی که از حاصل users و roles به وجود می آید role_user نام دارد. ولی چگونه باید این قرارداد را ما بسازیم برای همچین جداولی که به عنوان جدول واسط عمل می کنند.

اولین گام حروف الفبای انگلیسی را نوشته :

A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z

دومین گام نگاه می کنیم ببینیم بین جداول users و roles کدام حرف اولش از چپ به راست عقب تر از دیگری می باشد برای مثال من اگه بین حروف حرکت کنم R عقب تر از U می باشد پس جدول من می شود (roles_users) .

اخرین گام حال که جدول واسط از نام دو جدولی که باهم رابطه چند به چند دارن شکل گرفت فقط کافی است که جفت جدول ها را نام هایشان را منفرد کنیم به این شکل (role_user).

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

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The roles that belong to the user.
     */
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}

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

هنگامی که این رابطه را به درستی تعریف کردیم شکل استفاده آن به این شکل می شود :

$user = App\User::find(1);

foreach ($user->roles as $role) {
    //
}

برای محدود کردن آن ها هم برای نمایش اطلاعات به این شکل می شود :

$roles = App\User::find(1)->roles()->orderBy('name')->get();

خب حالا رابطه معکوس آن هم به این شکل ایجاد می کنیم :

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    /**
     * The users that belong to the role.
     */
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

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

برای استفاده از آن به این شکل عمل می کنیم در قطع کد زیر جدولی که حرفش را زدیم در قالب پراپرتی به نام pivot را مشاهد میکنید:

$user = App\User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

خب شکل کلی متد belongsToMany هم به این شکل می باشد :

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

ارگومان های ورودی این متد به این شکل می باشد :

۱. مدلی که میخواهید ارتباط دهید.

۲. جدول واسط که تعریف کرده اید.

۳. معرفی کلید خارجی در جدول واسط برای جدول کاربران.

۴. معرفی کلید خارجی در جدول واسط برای نقش ها.

نکته آخر اگر پارامتر های ۳و ۴ را ندهید طبق قرارداد خود لاراول user_id و role_id را در نظر می گیرد.

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

۲۰ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم ویژگی های جدید لاراول ۸ نوشت.

مقدمه

همانطور که میدانید آخرین نسخه Laravel 8.0 در September 8 منتشر شد. در این مقال قصد داریم ویژگی های جدیدی که در این فریم ورک محبوب و قدرتمند اضافه شده است را باهم برسی کنیم.

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

فقط نکته ای حائز اهمیتی که باید به آن اشاره کنم این است که Laravel در طی نسخه های انتشار داده، در نسخه 6 LTS طبق آماری که منتشر شده نسبت به سایر نسخه ها توسط لاراول پشتیبانی شده و مشکلات امنیتی و باگ های موجود و گزارش شده در آن رفع می شود و پایدارتر می باشد اگر نگاهی به جدول زیر بندازیم خواهیم فهمید نسخه 6 لاراول از نظر امنیتی تا سال 2022 پشتیبانی شده ولی با این حساب نمیشه از وپژگی های جدید لاراول گذشت.

ويژگی های جدید لاراول

بهترین ویژگی که در لاراول نسخه ۸ اضافه شد مفهومی به نام Jetstream می باشد که یک داربست کاربردی با طراحی بسیار زیبا برای لاراول است که می تواند یک نقطه شروع ایده آل برای پروژه شما باشد. حال علاوه بر این موارد زیر را به همراه داریم :

۱. Login/ Registration

۲. E-mail verification

۳. Two-factor authentication

۴. Session management

۵. API support via Laravel Sanctum

در ویژگی جدید لاراول همراه خود یک صفحه ورود جدید ارایه میدهد که دارای تم تیره و روشن می باشد که با استفاده از TailwindCSS ایجاد شده است.حالا بریم یکی یکی ویژگی ها جدید لاراول و معرفی کنیم.

Route Caching Improvements

این ویژگی ذخیره سازی مبتنی بر closure-based را پشتیبانی می کند‌، همانطور که میدانید قبل از لاراول ۸ ما می توانستیم مسیر های متنی بر کنترل ها را ذخیره کنیم و هر گونه closure-based و ایجاد بسته جدید باعث خرابی مسیر ذخیره می شود ولی حالا این مشکل در نسخه جدید لاراول حل شده است.

Route::get('/clear-cache-all', function() {
    Artisan::call('cache:clear');

    dd("Cache Clear All");
});

Dynamic Blade Components && attributes

در این بخش تمام child components ها داری ویژگی $attributes هستند، در لاراول ۷ هنگامی که یک کامپونت را گسترش می دهید دکمه فرزند خصوصیات $attributes را از خود نمی توانست رد کند.

<button {{'{{'}} $attributes }}>
   {{'{{'}} $slot }}
</button>

همانطور که مشاهده می کنید دکمه مورد نظر می تواند خصوصیات خود را به والدش معرفی کند. این ویژگی به شما کمک می کند تا اجزای قابل توسعه بسازید. گاهی اوقات شما نیاز دارید یک کامپونت را رندر کنید ولی نمی دانید که کدام جزء تا زمان رندر باید اجرا شود در همچین وضعیتی شما میتوانید از قابلیت جدید به نام x-dynamic-component برای رندر کردن کامپونت بر اساس مقدار اجرا یا متغییر استفاده کنید.

<x-dynamic-component :component="$componentName" class="mt-4" />

Migration Squashing

این ویژگی برای برنامه ها و یا مهاجرت های بزرگ پایگاه داده مفید می باشد، این ویژگی جدید که به نام Schema Dumping می باشد به شما کمک میکند که از پایگاه داده به خوبی نگهداری کنید. هنگامی که برنامه شما بزرگ می شود تعداد فایل های Migration شما هم به همان نسبت بزرگ می شود و نگهداری آن ها نسبتا سخت می کند به همین دلیل این ویژگی به شما کمک می کند با دستور زیر تمام آنها را در یک فایل SQL فشرده یا squash کنید. همچنین پایگاه داده های MySQL ، PostgreSQL و SQLite - همه از این ویژگی پشتیبانی می کنند.

php artisan schema:dump

// Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune

Models Directory

با توجه به تقاضای زیاد جامعه پشتیبانی لاراول پوشه پیش فرض model ها به مسیر app/Models منتقل شد و اگر این دایرکتوری وجود ندارد فریم ورک فرض می کند مسیر پیش فرض مدل های شما داخل پوشه app می باشد.

Model Factory Classes

ویژگی جدید model factories بر مبنای class based به طور کامل باز نویسی شده، این ویژگی در حال حاضر قوی تر و سازگار با توسعه دهندگان می باشد در این ویژگی برای هر مدل می تواند یک factory class وجود داشته باشد. به لطفا وجود trait جدید HasFactory در مدل ایجاد شده می توانید برای ایجاد تعداد مشخص از آن مانند روش زیر عمل کنید:

use App\Models\User;

User::factory()->count(50)->create();

متد definition مجموعه ای از ویژگی ها بر می گرداند، آن را در زیر مشاهده کنید:

class UserFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = User::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

از آنجایی که model factory های شما از نوع کلاس PHP ساده هستند همچنین می توانید تغییر حالت ها یا state transformations به عنوان متد در کلاس خود اضافه کنید و میتوانید هر کلاس کمکی دیگر را به Eloquent model factory اضافه کنید. به عنوان مثال، ممکن است مدل کاربر شما بخواهد به حالت تعلق یا suspended state در بیاید و یکی از ویژگی ها پیش فرض آن را تغییر بدهد. شما می توانید با استفاده از روش factory's state تغییرات حالت خود را تعریف کنید شما میتوانید روش حالت خود را با هر نامی که میخواهید نامگذاری کنید.

/**
 * Indicate that the user is suspended.
 *
 * @return \Illuminate\Database\Eloquent\Factories\Factory
 */
public function suspended()
{
    return $this->state([
        'account_status' => 'suspended',
    ]);
}

حتی این ویژگی به شما این امکان را می دهد که از model factory برای روابط بین جداول خود استفاده کنید.

$users = User::factory()
            ->hasPosts(3, [
                'published' => false,
            ])
            ->create();

Improved Rate Limiting

این ویژگی محدودیت نرخ یا Rate Limiting بهبود می بخشد، با این ويژگی میتواند مدیریت محدودیت نرخ را با انعطاف پذیری پیشرفته کنترل کنید. شما می توانید با استفاده از RateLimiter facade و متد for که یک توابع بازگشتی را بر می گرداند پیکربندی route هایی که باید محدود شوند را انجام دهید.

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000);
});

از آنجایی که تابع بازگشتی همراه خود HTTP را برمی گرداند شما میتوانید تمام درخواست ها را به صورت دینامیک دریافت کنید.

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

گاهی اوقات ممکن است بخواهید محدویت نرخ را با مقادیر دلخواه کنترل کنید برای مثال شاید شما بخواهید به کاربران اجازه دهید در هر 100 دقیقه در هر ادرس IP به یک مسیر مشخص دسترسی داشته باشند برای انجام این امر می توانید از کد زیر استفاده کنید.

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100)->by($request->ip());
});

همچنین میتوانید از ratelimiter خود به عنوان middleware در گروهی ازroute ها در لاراول استفاده کنید

Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        //
    });

    Route::post('/video', function () {
        //
    });
});

Job Batching

این ویژگی به شما این مکان را می دهد که دسته از jobs را به راحتی اجرا کنید و سپس بعد اتمام هر job برخی از اقدامات را انجام دهید. می توانید از متد batch از facade Bus برای ارسال دسته از job ها استفاده کنید و در هنگام بازگشت در صورت تکمیل فراخوانی از متد های then, catch, finally استفاده کنید.

$batch = Bus::batch([
    new ProcessPodcast(Podcast::find(1)),
    new ProcessPodcast(Podcast::find(2)),
    new ProcessPodcast(Podcast::find(3)),
    new ProcessPodcast(Podcast::find(4)),
    new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();

return $batch->id;

Routing Namespace Updates

در ویژگی های نسخه قبلی لاراول در فایل RouteServiceProvider دارای خصوصیتی به نام $namespace نامیده می شد. این پسوند فضای نامی یا namespace کنترلر های شما را تغیین می کرد.

لاراول ۸ این ویژگی را حذف کرده است و شما میتوانید کلاس های کنترل خود را بدون مشکل در فایل routes وارد کنید.
در نسخه های قبلی لاراول RouteServiceProvider دارای یک ویژگی به نام $namespace بود. مقدار این ویژگی به طور خودکار در تعاریف مسیر کنترل کننده و فراخوانی به action helper / URL::action اضافه می شود. در لاراول ۸، این ویژگی به طور پیش فرض خالی است. این بدان معناست که هیچ پیشوند فضای نام خودکار توسط لاراول انجام نمی شود. بنابراین ، در برنامه های جدید لاراول تعاریف مسیر کنترل کننده باید با استفاده از قاعده استاندارد PHP قابل فراخوانی باشد :

use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index']);

فراخوانی به روش های دیگر هم باید به شکل زیر باشد :

action([UserController::class, 'index']);

return Redirect::action([UserController::class, 'index']);

improved Maintenance Mode

در نسخه های قبلی لاراول ممکن است با استفاده از از دستور php artisan down برنامه خود را به حالت تعمیر ببرید و ممکن است آدرس های مجاز یا "allow list" از IP ها اجازه دسترسی به برنامه را داشته باشند. با استفاده از این ویژگی میتوانید با افزودن یک secret در نسخه 8 لاراول آن را امن کنید.

می توانید از این پس به شکل زیر از یک secret استفاده کنید:

php artisan down --secret="1630542a-246b-4b66-afa1-dd72a4c43515"

جمع بندی

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

۱۷ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم بهترین شیوه کد نویسی نوشت.

بهترین شیوه کد نویسی ( Best Coding Practice )

در این مقاله قصد دارم نکاتی که باعث می شود شما بهترین شیوه و سبک کد نویسی را در پروژه ها و سورس کد ها خود پیاده سازی کنید را بیان کنم.

همیشه اولین چیزی که در کد به چشم می آید مرتب بودن ساختار و نامگذاری ها و کامنت گذاری ها وغیره در سورس پروژه شما می باشد. لذا هر چه کد شما مرتب و استاندارد تر باشد باعث می شود بهتر ارایه دهید و در ضمن آن را به دیگران انتقال دهید، برای همین اکثر شرکت ها برنامه نویسانی که این اصول را رعایت می کنند را بهتر ترجیح می دهند.

مثلا در PHP قوانین برای این امر تعریف شده است به نام PSR که می توانید با کلیک کردن بر روی آن مستندات آن را مشاهده کنید.

من مخزنی را بر روی GitHub به شما معرفی میکنم که کد خوب و کد بد را در زبان JavaScript باهم مقایسه کرده است .

https://github.com/rezasaleki/clean-code-javascript

کتاب های متعددی هم در این زمینه وجود دارد که من میتوانم به یکی از معروف ترین ها که توسط Robert C.Martin نوشته شده است به نام The Clean Code اشاره کنم .

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

۱. همیشه متغییر ها و توابع خود را با نهایت دقت سعی کنید نام گذاری کنید و بطور کامل توضیح دهید.

۲. اسنادی برای سناریو فنی خود بسازید، حتی اگر مختصر یا توصیفی باشند.

۳. کدی که اجرا می شود کمتر از زمان خواندن آن وقت میگیرد پس سعی کنید همیشه برای شفافیت آن بیشتر زمان صرف کنید.

۴. هر تابعی که تعریف می کنید باید یک کار را انجام دهد ولی به درستی، این اصل به طراحی الگو یا Design Pattern و قوانین SOLID اشاره می کند که یک بند در آن به نام Single Responsibility Principle اشاره دارد.

۵. هر تابع باید به صورت Black Box عمل کند به این معنی که اگر کسی تابع شما را می بیند فقط از نام تابع متوجه فرایند آن شود و نیازی نباشد به بدنه آن سر بزند و از آن خبر داشته باشد.

۶. تا می توانید در سورس کد های خود از تعریف متغییر های سراسری امتناع کنید و آن ها را متصل به بلاک های خود نگهدارید.

۷. سعی کنید برای کد های خود علاوه بر تست های انسانی تست های سیستمی بنویسید که به عنوان مثال میتوانید در JavaScript به JestJS مراجعه کنید و برای PHP به PHPUnit مراجه کنید.

۸.شما هیچ وقت نمیتوانید 100% صحت کدی را که نوشته اید را تضمین کنید ولی با تست گرفتن و آزمون و خطا کردن می توانید تا حدی بالایی جلوی خطا های احتمالی را بگیرید.

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

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

۱۱. تا میتوانید توابع خود را به توابع کوچکتر بشکنید و وظایف آن ها را تا حدالممکن ساده تعریف کنید.

۱۲. برنامه خود را برای دیگران توضیح دهید این امر به شما کمک میکند خودتان بهتر آن را درک کنید.

۱۳. از VCS ها از قبیل Git در برنامه خود استفاده کنید تا تغییرات را در برنامه های شما همیشه دنبال کند و کارهای گروهی شما را سازماندهی کند.

نتیجه گیری

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

موارد ذکر شده در بالا از کتاب های کد نویسی تمیز و Data Structures and Program Design in C می باشد.

۱۶ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم Deploy Laravel Application توسط وب سرور Nginx نوشت.

مقدمه

در این مقاله قصد داریم که تمام پیکربندی های که هنگام راه اندازی اپلیکیشن لاراول، بر روی سرور Ubuntu 18.04 توسط وب سرور Nginx به آن ها نیاز دارید را آموزش دهیم.

نصب پیش نیازها بر روی سرور

۱. Nginx

2. PHP8

3. MySQL

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

هنگامی که شما یک سرور اشتراکی یا سرور VPS خریداری می کنید میتوانید از طریق telnet یا ssh به سرور خود ورود کنید، قبل از اجرای دستورات بر روی سرور می توانید برای telnet یا ssh کردن اگر سیستم عامل شما لینوکس است از دستورات زیر استفاده کنید :

نکته: البته سرور اشتراکی به شما پنل مدیریتی می دهد و میتوانید از طریق پنل خود هاستینگ به DirectAdmin یا Cpanel ورود کنید.

ssh -p 22 [email protected]
telnet ipserver

پس از ورود اولین دستور که اجرا می کنید به این صورت می باشد :‌ apt-get update، این دستور تمام مخزن های خود را بر روی سرور لینوکس بروز رسانی می کند

۱. Nginx

Nginx یکی از محبوب ترین وب سرور ها در جهان می باشد که وظیفه میزبانی برخی از بزرگترین و پر بازیدترین سایت های اینترنتی را برعهده دارد. در حال حاضر انتخاب بین Apache و Nginx بوده ولی بخاطر عملکرد و سرعت و امنیت و مدیریت منابع میتوان Nginx را به عنوان وب سرور و یا پروکسی معکوس معرفی کرد.

۱.۱ نصب Nginx

 apt-get install nginx

۱.۲تنظیم فایروال

قبل از راه اندازی Nginx باید تنظیمات مربوط به فایروال انجام شود تا دسترسی به ان امکان پذیر باشد. Nginx هنگام نصب خود را به عنوان یک سرویس به ufw معرفی می کند و این امر دسترسی به آن را ساده می کند.

تنظیمات برنامه فایروال را که ufw می داند با تایپ کردن دستور زیر لیست کنید :

ufw app list

شما باید فهرستی از مشخصات برنامه را به شکل زیر دریافت کنید :

//Output
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH

حال می توانید HTTP را با تایپ فعال کنید .

ufw allow Nginx HTTP

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

ufw status

خروجی :

//Output
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

۱.۳ برسی وضعیت وب سرور

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

systemctl status nginx

خروجی :‌

//Output
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2019-06-09 00:00:00 ; 3h 33min ago
     Docs: man:nginx(8)
  Process: 2062 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
  Process: 1803 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 2064 (nginx)
    Tasks: 5 (limit: 4915)
   CGroup: /system.slice/nginx.service
           ├─2064 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           ├─2066 nginx: worker process
           ├─2068 nginx: worker process
           ├─2071 nginx: worker process
           └─2072 nginx: worker process

اکنون اگر از طریق مرورگر خود IP سرور یا دامنه مورد نظر را تایپ کنید باید خروجی به شکل ذیل مشاهده کنید :

2.MySQL

اگر از اوبنوتو 18.04 استفاده می کنید به صورت پیش فرض در مخرن بسته APT موجود است، برای نصب آن از دستور زیر استفاده کنید.

apt-get install mysql-server

پس از نصب MySQL بر روی سرور خود از شما گذرواژه را نمی خواهد یا تغییرات پیکربندی دیگر را انجام دهید، اکنون این امر باعث می شود نصب MySQL ناامن باشد، برای همین امر دستور بعدی اجرا کنید.

 mysql_secure_installation

این امر ما را از طریق مجموعی از درخواست راهنمایی می کند که در آن می توانیم تغییراتی در گزینه های امنیتی نصب MySQL خود ایجاد کنیم. مانند تعیین رمزعبور برای کاربر اصلی و غیره. از طریق دستور زیر میتوانید برای کاربر اصلی یک رمزعبور تعیین کنید با دستورات SQL خود را جرا کنید.

mysql -u root -p

پس از انجام تمام فرایند های ذکر شده باید وضعیت فعال بودن سرویس MySQL خود را از طریق دستور بعدی چک کنید.

systemctl status mysql

خروجی :

// Output
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2019-06-09 00:00:00; 3h 53min ago
  Process: 1948 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid (code=exited, status=0/SUCCESS)
  Process: 1792 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 1950 (mysqld)
    Tasks: 28 (limit: 4915)
   CGroup: /system.slice/mysql.service
           └─1950 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid

و در آخر شما باید یک کاربر و دیتابیس ایجاد کنید بر روی سرویس MySQL خود که به ترییب دستورات زیر را وارد کنید .

۲.۱ ورود به MySQL

mysql -u root -p

۲.۲ تعریف کاربر جدید و اعمال دسترسی ها

mysql> GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password';

پس از ایجاد کاربر با دستور \q از سرویس MySQL خود خارج شوید و بعد با دستور بعدی با کاربر جدید وارد شوید.

mysql -u username -p

۲.۳ ایجاد دیتابیس

CREATE DATABASE dbname;

۳. PHP

اگر از اوبنوتو 18.04 استفاده می کنید به صورت پیش فرض در مخرن بسته APT موجود است، برای نصب آن از دستور زیر استفاده کنید.

sudo apt install php8.0

با دستور زیر از ورژن PHP نصب شده مطما شوید.

php -v

برای نصب PHP در کنار Nginx باید بسته FPM را نصب کنید .

sudo apt install php8.0-fpm

سپس تمام php-extensions های مورد نیاز را نصب کنید.

sudo apt install php8.0-common php8.0-mysql php8.0-xml php8.0-curl php8.0-gd php8.0-imagick php8.0-cli php8.0-dev php8.0-imap php8.0-mbstring php8.0-opcache php8.0-soap php8.0-zip -y

همانطور که می دانید توسط Composer تمام بسته های PHP مدیریت می شود، اکنون بعد از نصب موارد بالا حال می خواهیم Composer را هم نصب کنیم. دستورات زیر را به ترتیب اجرا کنید در بالا لینک نصب و پیکربندی از از روی سایت composer هم لینک داده شده است.

cd ~
curl -sS https://getcomposer.org/installer -o composer-setup.php

و بعد از آن توسط دستور زیر شروع به نصب کنید.

php composer-setup.php --install-dir=/usr/local/bin --filename=composer

در آخر با زدن دستور زیر شما composer را نصب دارید

composer

پیکربندی و راه اندازی برنامه

پس از انجام تمام موارد بالا مسیری که برای میزبانی برنامه های خود در نظر گرفته می شود در این مسیر /var/www/html می باشد. من با در نظر گرفتن اینکه شما Git را میدانید بقیه مقاله را ادامه می دهم، البته در یک مقاله دیگ سعی میکنم راه اندازی FTP سرور راه هم پوشش بدهم ولی فعلا مبنا Git می باشد .

با رفتن به مسیر /var/www/html مخزن خود را با دستور زیر clone کنید.

git clone https://github.com/username/project-name.git

سپس با دستورات زیر :

cp .env.example .env
nano .env

و باز کردن فایل .env میتوانید تمام تنظیمات خود را نسبت به سروری که پیکربندی کردین تغییر دهید.

حال برای نصب وابستگی ها بسته ها خود بر روی اپلیکیشن دستور زیر را اجرا کنید.

composer update

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

composer dump-autoload
php artisan config:clear
php artisan key:generate
php artisan migrate
php artisan db:seed

اکنون موقع آن رسیده است که پیکربندی لاراول را بر روی Nginx انجام دهیم که وب سرور ما درخواست ها به درستی مدیریت کند مسیری که به صورت پیش فرض خود Nginx تعیین کرده است این /etc/nginx/sites-available/default.conf مسیر می باشد. اولین دستور که باید تایپ کنید به شکل زیر می باشد :

nano /etc/nginx/sites-available/default.conf

تنظیمات زیر را جایگزین محتوای داخل فایل کنید :

// /etc/nginx/sites-available/default.conf file
server {
    listen 80;
    listen [::]:80;

    root /var/www/html/public;
    index index.php index.html index.htm index.nginx-debian.html;

    server_name <our.application.name>;

    location / {
    try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
      try_files $uri /index.php =404;
      fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

به جای کلمه server_name در تنظمیات باید دامنه یا IP سرور خود را قرار دهید.

حال فقط کافی است که یک symbolic link به مسیر /etc/nginx/sites-enabled/ ایجاد کنیم.

ln -S /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/

اکنون میتوانیم پیکربندی که انجام دادیم را با دستور زیر از صحت آن بر روی nginx مطما شویم و اگر پیغام زیر را دریافت کردید یعنی همچی به درستی انجام شده است.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

آخرین گامی که باید انجام دهید ریستارت کردن nginx است و اگر همچی به درستی انجام داده باشید سایت شما رور دامنه و یا IP بالا امده و میتوانید خدمات خود را به کابرانتان ارایه دهید.

systemctl restart nginx

کلام آخر

در این پست سعی کردم راهنمای کاملی به شما بدهم که چگونه می توانید برنامه Laravel خود را با Nginx در Ubuntu 18.04 در سرور به کار بگیرید. امیدوارم این مقاله به همه شما کمک کند.

۱۳ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم معرفی مفاهیم asynchronous, promises, async/await در جاوا اسکریپت نوشت.

یکی از مفاهیم نسبتا سخت و پیچیده که بیشتر اوقات باعث گیج شدن و سردرگمی برخی از برنامه نویسان می شود مفهوم غیرهمزمان یا Asynchronous می باشد .

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

این بخش سه قسمت دارد :

  1. asynchronous JS
  2. Promises
  3. async/await

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

موضوع غیر همزمان بودن در دو بخش سرور و کلاینت مورد اهمیت می باشد ولی در این مقاله بیشتر بر روی کلاینت تمرکز میکنم ولی در اینده حتما برای باز کردن مباحث بیشتر مایلم آن را به بخش سرور ببرم.

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

همانطور که در بالا مشاهده می کنید کنسول مقادیر را به ترتیب چاپ می کند.

برنامه های که با جاوا اسکرپیت نوشته می شوند معمولا تحت وب و رویداد محور هستن. به عبارت دیگر، جاوا اسکریپت تا زمانی که کاربر بر روی چیزی کلیک نکند یا ضربه نزد رویدادی اتفاق نمی افتد (سمت مشتری). در بخش دیگر که سرور قرار دارد و مبتنی بر JS می باشد منتظر می باشد که در سمت کلاینت از طریق اینترنت درخواستی به آن ارسال شود.

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

شما تصور کنید که تصویری با حجم زیادی از سمت سرور باید از بالای سایت شما بارگذاری شود، اگر سرور برای بارگذاری کردن این تصویر باید منتظر بمانند تا فرایند آن از سمت سرور به پایان برسد و بعد به سراغ بارگذاری بقیه محتوای سایت برود حتما این موضوع برای کاربر های شما جالب نمی باشد و عملکرد سایت شما را پایین می آرود زیرا نمی دانید این فرایند قرار است چقد طول بکشد.!

برنامه نویسی ناهمزمان توسط Callback ها

قبل از اینکه وارد Promise ها بشویم اساسی ترین مفهومی که باید بفهمیم فراخوانی می باشد (گذراندن یک تابع دیگر در یک تابع و هنگامی که شرایطی برآورده می شود یا رویدادی رخ می دهد، فراخوانی می شود).

همچنین روش قدیمی مدیریت برنامه نویسی ناهمزمان قبل از معرفی Promise در ES6 است. اما برخی از این callback ها هنوز معمولاً بدون promise دیده می شوند.

اولین آرگومان ()setTimeOut یک تابع callback و آرگومان دوم یک فاصله زمانی است که بر حسب میلی ثانیه اندازه گیری می شود.

معرفی Promise ها

Promises در ES6 برای ساده سازی برنامه نویسی ناهمزمان یا نامتقارن معرفی شدند. در این بخش به موارد زیر می پردازیم:

  • چرا promise ها معرفی شدند؟‌ (هشدار خرابکاری:‌ مشکل در فراخوانی و شلوغی callback ها)
  • تمام promise ها به ما قول میدهند که پاسخ را در سه حالت برگرداند : (then, catch, finally)

حال باید مثالی بزنیم شما تصور کنید در کافه ای میخواهید قهوه ای سفارش دهید در سه مرحله باید این فرایند اتفاق یبفتد ابتدا باید تصمیم بگیرید که چه نوع قهوه ای می خواهید، سپس سفارش خود را با باریستا ثبت کنید، سپس قهوه خود را دریافت کنید، آخرین و مهمترین، نحوه فراخوانی مجدد ظاهر می شود (اشاره به سند MDN در promise) :

chooseCoffee(function(order) {
  placeOrder(order, function(coffee) {
    drinkCoffee(coffee);
  }, failureCallback);
}, failureCallback);

ظاهر بسیار کثیفی دارد! این همان چیزی است که اغلب به عنوان callbacks-hell یا جهنم فراخوانی ها‍‍‍ نامیده می شود. promise ها اجازه می دهند این نوع callback های تو در تو به عنوان زنجیره promise مجدداً بیان شوند، که در ادامه مقاله بیشتر به آنها می پردازیم.

قاعد کلی تعریف promise به شکل زیر می باشد :

let promise = new Promise(function(resolve, reject) {
  // executor
});

آرگومان ها resolve و reject در callback آبجکت promise که توسط جاوا اسکریپت ارائه شده است فراخوانی می شوند.

در اینجا شما با سه مفهوم رو به رو می شوید که به شرح ذیل می باشد :‌

  • pending: هنگامی که promise ایجاد می شود، در حالت موفقیت یا شکست قرار می گیرد.
  • resolved: هنگامی که promise بازگشت داده می شود و در حالت حل شده قرار می گیرد.
  • fulfilled: هنگامی که promise با موفقیت حل می شود مقدار را برمیگرداند که میتوان با زنجیره زدن then به مقدار آن دسترسی پیدا کرد.
  • rejected:‌ هنگامی که promise بدون موفقیت حل می شود که یک پیغام خطا را برای رد شدن آن برمی گرداند که با زنجیره زدن catch به مقدار آن می توان دسترسی پیدا کرد.

شکل زیر نمایانگر فرایند اجرای promise می باشد:

قطعه کد زیر یک promise کامل را با تمام حالت ها نمایش میدهد :

let example = () => {
   return new Promise(function(resolve, reject) => {
     let value = function1();
     if (job success) {
       resolve(value);
     } else (job unsuccessful) {
       reject(console.log("something's wrong!! :("));
     }
   }).then(function(value)) {
     // success
     return nextFunction(value);
   }).catch(rejectFunction);
  }

مفهوم async / awiat

کلمات کلیدی async و await در ES2018 برای کاهش دیگر تکرارات و حل محدودیت "در شکستن زنجیره" در promise ها معرفی شد.

بیایید تفاوت بین Promises و async/await را ببینیم!

promise:

const promise = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve("done!"), 1000);
  })
};

async/await :

const promise = async () => {
  console.log(await promiseAsync());
};

در نتیجه هنگامی که از async/await استفاده می شود، then/catch به ندرت استفاده می شود. چرا که در درون خود مقادیر به صورت مستفیم به promise مورد نظر برمیگردند و دیگر نیازی به نوشتن زنجیره ای برای آنها نیست .

نتیجه گیری

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

۱۲ شهریور، ۱۴۰۰

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم مفاهیم اولیه Node.js نوشت.

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

Node js در سال ۲۰۰۹ توسط Ryan Dahl توسعه دهنده وب ایجاد شد چرا که در هنگام توسعه به جریان ورودی خروجی های شدید و برنامه نویسی همزمان و سیستم عامل های چند رشته در سمت سرور با مشکلات شدید روبرو شد.

بنابراین نود جی اس فناروی است برای حله مقابله با رویدادهای ورودی و خروجی (intense I/O) ناهمزمان شدید، خب بهترین زبان که ظرفیت این کار را دارد نیز جاوااسکریپت است.

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

۱. نود جی اس چیست ؟

به زبان ساده بخواهم برایتان بگویم یک پلتفرم منبع باز جاوا اسکریپت برای برنامه نویسی سمت سرور است که بر روی موتور Chrome's V8 JavaScript ساخته شده است، به این معنی که موتور جاوا اسکرپیت را در مروگر وب کامپایل می کند و همانطور موتور نود جی اس را در آن اجرا می کند.

چنین هسته ای در کنار مروگر باعث می شود برنامه های تحت وب که با نود جی اس نوشته شده است با سرعت بالا اجرا بشوند.

۲. چرا نود جی اس ؟

نود جی اس یک پلتفرم قدرتمند برای توسعه برنامه های مدرن وب در سمت سرور می باشد! این زبان بخاطر پایدار بودن و قابل اعتماد بودن مورد توجه شرکت های جهانی از قبیل : Netflix, Uber, LinkedIn and PayPal .

معماری های رویداد محور به دلیل ویژگی های تک رشته ای (Single-Thread) همراه با یک پلتفرم چند رشته ای (Multi-Thread) که در پس زمینه اجرا می شود این زبان برای برنامه های با ورودی و خروجی (intense I/O) شدید بسیار مناسب است که این امر باعث بهبود عملکرد و کمتر شدن سخت افزار برای خدمات به مشتریان می شود.

2.1 Non-Blocking I/O

روش غیر مسدود کردن (Non-Blocking) یک ورودی را دریافت کرده و خروجی را به صورت ناهمزمان برمی گرداند، این عمل برای سرور این امکان فراهم می کند که بتواند تعداد زیادی درخواست را بدون مسدود کردن برنامه دریافت کند، در حالی که پاسخ در پس زمینه پردازش می شود.

2.2 Single Thread

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

این ویژگی با استفاده از حافظه کم و ظرفیت زیر ساختی برای پردازش تعداد زیادی از درخواست ها آن را سبک، مقایس پذیر و کارامد می کند.

۲.۳ Event Driven

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

بنابراین در لحظه که یک برنامه تحت Node شروع به کار می کند یک شنونده رویداد به نام Event Loop شروع به انتظار رویداد می کند و تا خاموش شدن برنامه متوقف نمی شود. به عنوان مثال یک پیشخدمت رستوان که در هر لحظه آماده دریافت سفارش مشتری تا زمان بسته شدن رستوران باشد.

تصویری که در پایین مشاهد می کنید چرخه حیات رویداد مشخص می کند.

۲.۴ Node Package Manager

Node Package Manager بزرگ ترین کتابخانه متن باز در جهان است تمام ابزار های که برای برنامه در حال توسعه خود با نود جی اس نیاز دارید را میتوانید توسط آن نصب و استفاده کنید و حتی اگر بخواهید میتوانید بسته های را برای خود توسعه داده و به عنوان یک کتابخانه بر روی آن قرار دهید تا بقیه توسعه دهندگان از آن استفاده کنند.

۲.۵ No Buffering

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

2.6 Scalable

مقیاس پذیری ویژگی اصلی نود می باشد، زیرا ظرفیت بالایی در رسیدگی به حجم زیادی از درخواست ها را به صورت غیرهمزمان با زیر ساخت کم از طریق معماری آن دارد.

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

۳ Architecture Node.js

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

فرض کنید یک مشتری چندین درخواست به این برنامه ارسال می کند:

۳.۱ Event Queue

به محض رسیدن این درخواست ها به برنامه، آنها به صف رویداد (Event Queue) می روند، صفی که در آن تمام رویداد های رخ داده در برنامه اتفاق می افتد و در آنجا منتظر ارسال شدن هستند، آنها برای پردازش در چرخه ای به نام Event Loop به سر می برند.

۳.۲ Event Loop

همگامی که یک درخواست (عملیات مسدود سازی) در حلقه رویداد وارد می شود، یک پلتفرم تک رشته ای است که موتر ٰV8 در هسته خود برای کامپایل جاوااسکرپیت اجرا می کند، بعد از آن به پلتفرم Thread Pool واگذار می شود تا در پس زمینه پردازش شود، بنابراین با این جریان معماری نخ اصلی برای رسیدگی به بقیه رویداد ها در دسترس قرار می گیرد.

۳.۳ Thread Pool

یک پلتفرم چند رشته ای است که کتابخانه ای به نام libuv را اجرا می کند و C++ را در هسته خود دارد، درخواست (Blocking Operation) به صورت ناهمزمان در پس زمینه پردازش اجرا می شود تا کامل شود و اماده بازگشت باشد.

نتیجه گیری

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

در دنیایی مدرن و فوق العاده متصل به هم، فناوری ای که بتواند با زیرساخت های پایین به سرعت مقیاس بندی شود، مطمئناً مهره مهمی است که باید به آن توجه کرد.

٢ سال پیش ١۵۰۰+ امتیاز
نویسنده @reskipper یک مقاله تازه به اسم ۸ دلیل که چرا PHP هنوز برای توسعه دهندگان مهم است نوشت.

PHP یک زبان سمت سرور است که بیش از ۲۵ سال است که وجود دارد و امروزه تمایل زیاد دارد که نظرات قوی را در میان توسعه دهندگان برانگیزد که چرا از زبان پی اچ پی استفاده می شود.!

هر زمان که یک زبان برنامه نویسی یا ابزار جدید ظاهر می شود، شما احتمالا در انجمن ها و گفتگو ها در مورد این می شنوید که PHP مرده است.!

این درست است که PHP بین رتبه بندی محبوب ترین زبان های برنامه نویسی از نظر رتبه در سال ۲۰۰۷ (رتبه ۵) و در سال ۲۰۲۰ در رتبه (۸) در میان توسعه دهندگان سایت Stack Overflow قرار گرفته است و این یک روند رو به کاهش بوده است ولی با این وجود تقریبا ۸۰٪ از همه وب سایت ها از PHP استفاده می کنند و حتی برخی از پتلفرم های اصلی مثل وردپرس و یا facebook هنوز از آن استفاده می کنند.

تصویر بالا نمایان این است که چه ترافیکی توسط چه زبان های از سایت های مختلف عبور کرده است.

چرا PHP هنوز به صورت گسترده استفاده می شود ؟

هماهنطور که می دانید PHP (Hypertext Preprocessor) یک ابر پردازنده متن می باشد و به عنوان یک زبان برنامه نویسی همه منظوره شناخته می شود که می تواند برای توسعه وب سایت ها پویا و تعاملی مورد استفاده قرار گیرد. زبان PHP یکی از اولین زبان های بود که میتوانست در بین HTML جایگذاری شود، و این امکان این شرایط و فراهم می کرد بدون نیاز به فراخوانی داده ها و استخراج کردن آنها، کد های PHP را در بین تگ ها HTML به صورت آسان استفاده کنیم.

استفاده از PHP در طی سالها تکامل یافته است و حالا با ارتقاء مداوم (نسخه PHP 8.0 در نوامبر ۲۰۲۰ منتشر شد) آن ویژگی ها جدید اضافه کرده و قفل قابلیت ها جدید در بین زبان ها دیگر را باز کرده است.

<!DOCTYPE html> 
<html> 
  <head>
    <title>Example</title>
 </head>
<body>
  <!--?php echo "Hi, I'm a PHP script!"; ?--> 
</body> 
</html>

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

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

۲. متن باز است (open source) :‌ این به توسعه دهندگان کمک می کند تا با زبان PHP شروع به کار کنند، می توان آن را به سرعت و بدون هزینه نصب کرد.

همچنین دسترسی باز به طیف گسترده ای از چهارچوب های PHP از قبیل :‌ Laravel و Symfony می توان اشاره کرد. این ویژگی برای بسیاری از شرکت ها جذاب است زیرا به کنترل هزینه های توسعه وب کمک می کند.

۳. همه کاره است : یکی از مهمترین مزیت های PHP مستقل بودن از پلتفرم می باشد، به این معنی که می توان آن را در سیستم عامل های مختلف از قبیل Mac ، Windows ، Linux و اکثر مروگر های وب استفاده کرد و همچنین از اکثر وب سرور های اصلی پشتیبانی می کند و استقرار آن در سیستم ها و سیستم عامل های مختلف را با حداقل هزینه اضافی آسان می کند.

۴.از پشتیبانی جامعه قوی برخوردار است (community) :‌ به عنوان یک زبان برنامه نویسی قدیمی که به طور گسترده مورد استفاده قرار می گیرد PHP دارای یک پایگاه اجتماعی بزرگ و وفادار می باشد که از آن حمایت می کنند در آن تعداد زیادی آموزشی و پرسش و پاسخ و راهنمایی وجود دارد که به توسعه دهندگان جدید کمک می کند تا آسان تر مسیر خود را برای یادگیر پیدا کنند این مسیر از طریق بروز رسانی های که PHP انجام می دهد همیشه ادامه دارد.

۵.سریع و ایمن است:‌ دو مورد از ویژگی ها که سازمان ها میخواهند جزو ویژگی زبان توسعه آنها باشد ایمن و سریع بودن آن زبان است، PHP از حافظه خود استفاده می کند و این امر از نظر سرعت می تواند به خوبی رقابت کند، همچنین در ورژن های جدید PHP از نظر امنیت در جایگاه بالاتری نسبت به ورژن های قدیمی تر دارا می باشد.

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

۶. اتصال به پایگاه داده : PHP اتصال ایمن را تقریبا با هر نوع پایگاه داده آسان می کند، این امر به توسعه دهندگان آزادی بیشتر می دهد تا انتخاب کنند که کدام پایگاه داده در حال توسعه بهتر می باشد.

۷. آزمایش شده است : بدین معنی می باشد که کدهای PHP در یک ربع قرن اول در محیط های واقعی آزمایش شده است و اشکالات اصلی پیدا شده و برطرف شده است و این امر باعث می شود زبان مورد نظر در بین توسعه دهندگان مورد اعتماد باشد.

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

۸. کد های قدیمی PHP وجود دارد : این امر به تنهایی مزیت محسوب نمی شود بلکه وقتی تعداد زیادی از وب سایت های موجود با PHP نوشته شده اند به یک ملاحضه مهم تبدیل می شود، به زبان آسان تر بهتر است بروز رسانی ها را با یک زبان انجام دهید تا این که با یک زبان دیگر همه چیز را باز نویسی کنید، این امر به خودی خود کمک می کند که توسعه دهندگان آن بجای مهاجرت از یک زبان جدید دیگر خود زبان اصلی که با آن سرویسی را توسعه داده اند را بروز رسانی کند.

همچنین یافتن افرادی که توسعه زبان PHP را انجام میدهند آسان تر هست ولی در صورت که مهارت های لازمه را داشته باشند.

نتیجه گیری

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