۹ دی، ۱۴۰۰
نویسنده @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
بین روابط جداول قرارداد کرده است را باهم برسی کنیم.
انواع روابط در لاراول
One To One
(یک به یک)One To Many
(یک به چند)Many To Many
(چند به چند)Has One Through
(یک به یک واسطه ای)Has Many Through
(یک به چند واسطه ای)One To One (Polymorphic)
(یک به یک پلی مورفیک)One To Many (Polymorphic)
(یک به چند پلی مورفیک)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
می باشد .
در اکثر مصاحبه ها دیده می شود که این مفهوم مورد سوال قرار میگیرد، من قصد دارم که این مبحث را یکبار باز کرده تا کسانی که میخواهند درکی از برنامه نویسی ناهمزمان داشته باشند کمکی کرده باشم.
این بخش سه قسمت دارد :
asynchronous JS
Promises
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
را انجام میدهند آسان تر هست ولی در صورت که مهارت های لازمه را داشته باشند.
نتیجه گیری
در نهایت، زبان انتخاب شما بستگی به این دارد که میخواهید که چه چیزی را بسازید و چه ویژگی های را در اولویت قرار دهید.