۱۳۹۹/۰۴/۱۹

سرویس های در فریم ورک سیمفونی

Service Container in Symfony ۱۳۹۸/۰۵/۲۹

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

در سیمفونی یکی از پرکاربرد ترین این Object ها service ها هستند.هر سرویس در داخل یک object خاص به نام service container قرار دارند.اگر شما دسترسی لازم به service container را داشته باشید میتوانید به هر سرویسی که نیاز دارید دسترسی داشته باشید و از آن استفاده کنید.

// src/Controller/ProductController.php
// ...
use Psr\Log\LoggerInterface;
/**
 * @Route("/products")
 */
public function list(LoggerInterface $logger)
{
    $logger->info('Look! I just used a service');

    // ...
}

در واقع service container مانند یک جعبه ابزار است که service های دیگر را در خود جای داد.شما براحتی میتوانید در کنترلر خود سرویس مورد نظر خود را از  container درخواست کنید.

سرویس های را می توان از طریق Id یا type-hinting یک آرگومنت (argument ) و یا نام کلاس سرویس یا انترفیس فراخوانی کنید.بطور مثال اگر نیاز به log داشته باشید طبق مثال زیر آنرا در کنترلر خود فراخوانی میکنید.

// src/AppBundle/Controller/ProductController.php
// ...
use Psr\Log\LoggerInterface;
/**
 * @Route("/products")
 */
public function listAction(LoggerInterface $logger)
{
    $logger->info('Look! I just used a service');
    // ...
}

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

 php bin/console debug:container

=============================== ==================================================================
Service ID                      Class name
=============================== ==================================================================
doctrine                        Doctrine\Bundle\DoctrineBundle\Registry
filesystem                      Symfony\Component\Filesystem\Filesystem
form.factory                    Symfony\Component\Form\FormFactory
logger                          Symfony\Bridge\Monolog\Logger
request_stack                   Symfony\Component\HttpFoundation\RequestStack
router                          Symfony\Bundle\FrameworkBundle\Routing\Router
security.authorization_checker  Symfony\Component\Security\Core\Authorization\AuthorizationChecker
security.password_encoder       Symfony\Component\Security\Core\Encoder\UserPasswordEncoder
session                         Symfony\Component\HttpFoundation\Session\Session
translator                      Symfony\Component\Translation\DataCollectorTranslator
twig                            Twig\Environment
validator                       Symfony\Component\Validator\Validator\ValidatorInterface
=============================== ==================================================================

همچنین شما میتوانید از طریق نام منحصر بفرد Service ID بطور مستقیم به سرویس مورد نظر خود دسترسی داشته باشید.

// src/AppBundle/Controller/ProductController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends Controller
{
    /**
     * @Route("/products")
     */
    public function listAction()
    {
        $logger = $this->container->get('logger');
        $logger->info('Look! I just used a service');

        // ...
    }
}

واکشی یا فراخوانی سرویس بطور مستقیم از طریق Service ID از Container تنها زمانی امکان دارد که کلاس شما از یک کلاس Controller ,مشتق یا extend شده باشد.

سرویس های در فریم ورک سیم فونی

نکته: به این نکته توجه داشته باشید که همه سرویس ها در Container در برنامه لود نمیشوند.تنها زمانی یک سرویس در برنامه لود میشود که ان را صدا بزنید .در غیر اینصورت هرگز از ظرف Container خارج نمی شوند  و تا ابد در ان قفسه اهنی اسیر خواهند ماند.

ساخت سرویس سفارشی در سیمفونی

در سیمفونی فریم ورک شما میتوانید سرویس های سفارشی سازی شده خود را برای انجام پردازش های مورد نظر خود ایجاد کنید.

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

use AppBundle\Service\MessageGenerator;
public function newAction(MessageGenerator $messageGenerator)
{
    // thanks to the type-hint, the container will instantiate a
    // new MessageGenerator and pass it to you!
    // ...

    $message = $messageGenerator->getHappyMessage();
    $this->addFlash('success', $message);
    // ...
}

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

use App\Service\MessageGenerator;

public function new(MessageGenerator $messageGenerator)
{
    // thanks to the type-hint, the container will instantiate a
    // new MessageGenerator and pass it to you!
    // ...

    $message = $messageGenerator->getHappyMessage();
    $this->addFlash('success', $message);
    // ...
}

زمانیکه شما سرویس MessageGenerator  را فراخوانی میکنید.container یک شی MessageGenerator ایجاد میکند.و نتیجه پردازش را برمی گرداند.

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

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

در این آموزش فرض شده که شما از سیمفونی نسخه 3.4 استفاده میکنید و services.yaml برنامه شما مانند مقادیر زیر تنظیم شده است 

# app/config/services.yml
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    # makes classes in src/AppBundle available to be used as services
    AppBundle\:
        resource: '../../src/AppBundle/*'
        # you can exclude directories or files
        # but if a service is unused, it's removed anyway
        exclude: '../../src/AppBundle/{Entity,Repository}'

با این تنظیمات در فایل  services.yaml برنامه به کلیه کلاس ها در پوشه src/AppBundle/ دسترسی دارد و نیازی نیست هر سرویس را بصورت دستی در این فایل مشخص کنید .ولی اگر شما نیاز به سرویس خاصی داشتید که ان سرویس مثلا نیاز به ارگمانت یا مقدار خاصی برای اجرا داشت باید آنرا صریحا در این فایل مشخص کنید.

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

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

use AppBundle\Service\MessageGenerator;

// accessing services like this only works if you extend Controller
class ProductController extends Controller
{
    public function newAction()
    {
        // only works if your service is public
        $messageGenerator = $this->get(MessageGenerator::class);

        $message = $messageGenerator->getHappyMessage();
        $this->addFlash('success', $message);
        // ...
    }
}

تنها زمانیکه سرویس public باشد میتوانید از این روش استفاده کنید.

Service Parametersدر سیمفونی

service container علاوه بر نگهداری سرویس ها.قابلیت های دیگری هم برای پیکربندی دارد.یکی از این قابلیت های parameters است.برای استفاده از پارامتر ها در زیر کلمه کلیدی parameters  از سینتکس %parameter_name% استفاده کنید.

# app/config/services.yml
parameters:
    admin_email: manager@example.com

services:
    # ...

    AppBundle\Updates\SiteUpdateManager:
        arguments:
            $adminEmail: '%admin_email%'

با استفاده از کد بالا شما یک پارامتر به سرویس خود تزریق کرده اید و میتواند در کلاس سرویس از آن استفاده کنید .مقدار دهی این پارامتر را باید در فایل parameters.yml تنظیم کنید.

parameters:
    # ...
    admin_email: pedramham1@gmail.com

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

class SiteUpdateManager
{
    // ...
    private $adminEmail;
    public function __construct($adminEmail)
    {
        $this->adminEmail = $adminEmail;
    }
}

نکته :پارامتر ها را متوان بصورت مستقیم نیز تعریف کرد بدون اینکه در فایل  parameters.yml تعریف شوند.البته برای حفظ ساختار برنامه بهتر است که از روش بالا استفاده کنید.اگر میخواهید رشته ای تزریق کنید که در ابتدای رشته از کاراکتر % استفاده شده باید برای تعریف اینگونه رشته ها از یک علامت % دیگر در ابتدای رشته استفاده کنید.

# app/config/parameters.yml
parameters:
    #ذخیره میشود '%securepass' رشته 
    mailer_password: '%%securepass'

رای :

سرویس

سیموفنی

service container

فریم ورک سیم فونی

Object

ارسال نظر
Copyright © All right reserved.