Basit Bağlamalar

Hizmet konteyneri bağlamalarınızın neredeyse tamamı hizmet sağlayıcıları içinde kayıtlı olacaktır, bu nedenle bu örneklerin çoğu konteyneri bu bağlamda kullanmayı gösterecektir.

Bir hizmet sağlayıcısı içinde, konteynere her zaman $this->app özelliği aracılığıyla erişebilirsiniz. Bind yöntemini kullanarak bir bağlama kaydedebiliriz, kaydetmek istediğimiz sınıf veya arayüz adını ve sınıfın bir örneğini döndüren bir kapatmayı geçirebiliriz:

use App\Services\RokitoTransistor;
use App\Services\RokitoParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(RokitoTransistor::class, function (Application $app) {
    return new RokitoTransistor($app->make(RokitoPodcastParser::class));
});
Konteynerin kendisini çözücüye bir argüman olarak aldığımızı unutmayın. Daha sonra konteyneri, oluşturduğumuz nesnenin alt bağımlılıklarını çözmek için kullanabiliriz.

Tek Bir Öğeyi Bağlama (Singleton)

Singleton yöntemi, yalnızca bir kez çözülmesi gereken bir sınıfı veya arayüzü konteynera bağlar. Bir singleton bağlaması çözüldüğünde, konteynera yapılan sonraki çağrılarda aynı nesne örneği döndürülür:

use App\Services\RokitoTransistor;
use App\Services\RokitoParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->singleton(RokitoTransistor::class, function (Application $app) {
    return new RokitoTransistor($app->make(RokitoParser::class));
});
singletonIf metodunu, yalnızca belirtilen tür için daha önce bir bağlama kaydedilmemişse tekil bir kapsayıcı bağlamasını kaydetmek için kullanabilirsiniz:

$this->app->singletonIf(RokitoTransistor::class, function (Application $app) {
    return new RokitoTransistor($app->make(RokitoParser::class));
});
Kapsamlı Tekilleri Bağlama (Scoped Singletons)

Kapsamlı yöntem, belirli bir Laravel isteği/iş yaşam döngüsü içinde yalnızca bir kez çözülmesi gereken bir sınıfı veya arayüzü konteynera bağlar. Bu yöntem singleton yöntemine benzer olsa da, kapsamlı yöntem kullanılarak kaydedilen örnekler, Laravel uygulaması yeni bir "yaşam döngüsü" başlattığında, örneğin bir Laravel Octane çalışanı yeni bir isteği işlediğinde veya bir Laravel kuyruk çalışanı yeni bir işi işlediğinde temizlenir:

use App\Services\RokitoTransistor;
use App\Services\RokitoParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->scoped(RokitoTransistor::class, function (Application $app) {
    return new RokitoTransistor($app->make(RokitoParser::class));
});
Kapsamlı bir kapsayıcı bağlamayı kaydetmek için scopedIf yöntemini yalnızca belirtilen tür için daha önce bir bağlama kaydedilmemişse kullanabilirsiniz:

$this->app->scopedIf(RokitoTransistor::class, function (Application $app) {
    return new RokitoTransistor($app->make(RokitoParser::class));
});
Bağlayıcı Örnekler

Ayrıca, instance metodunu kullanarak var olan bir nesne örneğini konteynera bağlayabilirsiniz. Verilen örnek, konteynera yapılan sonraki çağrılarda her zaman döndürülecektir:

use App\Services\RokitoTransistor;
use App\Services\RokitoParser;

$rokitoService = new RokitoTransistor(new RokitoParser);

$this->app->instance(RokitoTransistor::class, $rokitoService);
Arayüzleri Uygulamalara Bağlama

Servis konteynerinin çok güçlü bir özelliği, bir arayüzü belirli bir uygulamaya bağlama yeteneğidir. Örneğin, bir RokitoPusher arayüzümüz ve bir RokitoEventPusher uygulamamız olduğunu varsayalım. Bu arayüzün RokitoEventPusher uygulamasını kodladıktan sonra, bunu servis konteynerine şu şekilde kaydedebiliriz:

use App\Contracts\RokitoPusher;
use App\Services\RokitoEventPusher;

$this->app->bind(RokitoPusher::class, RokitoEventPusher::class);
Bu ifade, bir sınıfın RokitoEventPusher uygulamasına ihtiyacı olduğunda konteyneraRokitoEventPusher'ı enjekte etmesi gerektiğini söyler. Şimdi, konteyner tarafından çözülen bir sınıfın kurucusunda RokitoPusher arayüzünü tür ipucuyla belirtebiliriz. Unutmayın, Laravel uygulamalarındaki denetleyiciler, olay dinleyicileri, ara yazılımlar ve çeşitli diğer sınıf türleri her zaman konteyner kullanılarak çözülür:

use App\Contracts\RokitoPusher;

/**
 * Create a new class instance.
 */
public function __construct(
    protected RokitoPusher $rokitoPusher,
) {}
Bağlamsal Bağlama

Bazen aynı arayüzü kullanan iki sınıfınız olabilir, ancak her sınıfa farklı uygulamalar enjekte etmek isteyebilirsiniz. Örneğin, iki denetleyici IlluminateContractsFilesystemFilesystem sözleşmesinin farklı uygulamalarına bağlı olabilir. Laravel bu davranışı tanımlamak için basit ve akıcı bir arayüz sağlar:

use App\Http\Controllers\PhotoController;
use App\Http\Controllers\UploadController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;

$this->app->when(PhotoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('local');
    });

$this->app->when([VideoController::class, UploadController::class])
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('s3');
    });
Bağlamsal Nitelikler

Bağlamsal bağlama genellikle sürücülerin veya yapılandırma değerlerinin uygulamalarını enjekte etmek için kullanıldığından, Laravel, servis sağlayıcılarınızda bağlamsal bağlamaları manuel olarak tanımlamadan bu tür değerleri enjekte etmenize olanak tanıyan çeşitli bağlamsal bağlama nitelikleri sunar.

Örneğin, Depolama niteliği belirli bir depolama diskini enjekte etmek için kullanılabilir:

<?php

namespace App\Http\Controllers;

use Illuminate\Container\Attributes\Storage;
use Illuminate\Contracts\Filesystem\Filesystem;

class PhotoController extends Controller
{
    public function __construct(
        #[Storage('local')] protected Filesystem $filesystem
    )
    {
        // ...
    }
}
Laravel, Storage niteliğine ek olarak Auth, Cache, Config, DB, Log, RouteParameter ve Tag niteliklerini de sunar:

<?php

namespace App\Http\Controllers;

use App\Models\Photo;
use Illuminate\Container\Attributes\Auth;
use Illuminate\Container\Attributes\Cache;
use Illuminate\Container\Attributes\Config;
use Illuminate\Container\Attributes\DB;
use Illuminate\Container\Attributes\Log;
use Illuminate\Container\Attributes\RouteParameter;
use Illuminate\Container\Attributes\Tag;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Database\Connection;
use Psr\Log\LoggerInterface;

class PhotoController extends Controller
{
    public function __construct(
        #[Auth('web')] protected Guard $auth,
        #[Cache('redis')] protected Repository $cache,
        #[Config('app.timezone')] protected string $timezone,
        #[DB('mysql')] protected Connection $connection,
        #[Log('daily')] protected LoggerInterface $log,
        #[RouteParameter('photo')] protected Photo $photo,
        #[Tag('reports')] protected iterable $reports,
    )
    {
        // ...
    }
}
Ayrıca Laravel, şu anda kimliği doğrulanmış kullanıcıyı belirli bir rotaya veya sınıfa eklemek için bir CurrentUser niteliği sağlar:

use App\Models\User;
use Illuminate\Container\Attributes\CurrentUser;

Route::get('/user', function (#[CurrentUser] User $user) {
    return $user;
})->middleware('auth');
Özel Nitelikleri Tanımlama

IlluminateContractsContainerContextualAttribute sözleşmesini uygulayarak kendi bağlamsal niteliklerinizi oluşturabilirsiniz. Kapsayıcı, niteliğinizin çözümleme yöntemini çağıracaktır; bu, niteliği kullanarak sınıfa enjekte edilmesi gereken değeri çözümlemelidir. Aşağıdaki örnekte, Laravel'in yerleşik Config niteliğini yeniden uygulayacağız:

<?php

namespace App\Attributes;

use Attribute;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Container\ContextualAttribute;

#[Attribute(Attribute::TARGET_PARAMETER)]
class Config implements ContextualAttribute
{
    /**
     * Create a new attribute instance.
     */
    public function __construct(public string $key, public mixed $default = null)
    {
    }

    /**
     * Resolve the configuration value.
     *
     * @param  self  $attribute
     * @param  \Illuminate\Contracts\Container\Container  $container
     * @return mixed
     */
    public static function resolve(self $attribute, Container $container)
    {
        return $container->make('config')->get($attribute->key, $attribute->default);
    }
}
Bağlayıcı İlkeller

Bazen bazı enjekte edilmiş sınıfları alan, ancak aynı zamanda bir tamsayı gibi enjekte edilmiş bir ilkel değere ihtiyaç duyan bir sınıfınız olabilir. Sınıfınızın ihtiyaç duyabileceği herhangi bir değeri enjekte etmek için bağlamsal bağlamayı kolayca kullanabilirsiniz:

use App\Http\Controllers\UserController;

$this->app->when(UserController::class)
    ->needs('$variableName')
    ->give($value);
Bazen bir sınıf, etiketli örneklerin dizisine bağlı olabilir. giveTagged yöntemini kullanarak, tüm kapsayıcı bağlamalarını bu etiketle kolayca enjekte edebilirsiniz:

$this->app->when(ReportAggregator::class)
    ->needs('$reports')
    ->giveTagged('reports');
Uygulamanızın yapılandırma dosyalarından birinden bir değer eklemeniz gerekiyorsa giveConfig metodunu kullanabilirsiniz:

$this->app->when(ReportAggregator::class)
    ->needs('$timezone')
    ->giveConfig('app.timezone');
Bağlayıcı Tipli Variadikler

Bazen, değişkenli bir oluşturucu bağımsız değişkeni kullanarak bir dizi türü nesnesi alan bir sınıfınız olabilir:

<?php

use App\Models\Filter;
use App\Services\Logger;

class Firewall
{
    /**
     * The filter instances.
     *
     * @var array
     */
    protected $filters;

    /**
     * Create a new class instance.
     */
    public function __construct(
        protected Logger $logger,
        Filter ...$filters,
    ) {
        $this->filters = $filters;
    }
}
[B][/B]


Bağlamsal bağlamayı kullanarak, give yöntemine çözümlenmiş Filtre örneklerinin bir dizisini döndüren bir kapanış sağlayarak bu bağımlılığı çözebilirsiniz:

$this->app->when(Firewall::class)
    ->needs(Filter::class)
    ->give(function (Application $app) {
          return [
              $app->make(NullFilter::class),
              $app->make(ProfanityFilter::class),
              $app->make(TooLongFilter::class),
          ];
    });
Kolaylık olması açısından, Güvenlik Duvarı Filtre örneklerine ihtiyaç duyduğunda, kapsayıcı tarafından çözülecek sınıf adlarının bir dizisini de sağlayabilirsiniz:

$this->app->when(Firewall::class)
    ->needs(Filter::class)
    ->give([
        NullFilter::class,
        ProfanityFilter::class,
        TooLongFilter::class,
    ]);
Değişken Etiket Bağımlılıkları

Bazen bir sınıfın, belirli bir sınıf olarak tür ipucuyla işaretlenmiş değişken bir bağımlılığı olabilir (Report ...$reports). needs ve giveTagged yöntemlerini kullanarak, belirtilen bağımlılık için tüm kapsayıcı bağlamalarını bu etiketle kolayca enjekte edebilirsiniz:

$this->app->when(ReportAggregator::class)
    ->needs(Report::class)
    ->giveTagged('reports');