Laravel 101

Makale İçerik Listesi

Migration

  1. Index eklerken 
    $table->string('name')->index();
  2. Foreign Key constraint eklerken 1.yol
    // eğer bağlı olduğu yer natural bağlı olacağı yer ise
    $table->foreignId('company_id')->constrained();
    
    // eğer bağlı olduğu yer natural bağlı olacağı yer değil ise tablo adını yaz
    $table->foreignId('company_id')->constrained('stores');

    2. yol 

    $table->unsignedBigInteger('role_id')->default(1);
    $table->foreign('role_id')->references('id')->on('roles');
  3. Foreign Key üzerinden cascade işlemi yapmak istersek 
    $table->foreignId('user_id')
          ->constrained()
          ->onUpdate('cascade')
          ->onDelete('cascade');
  4. Foreign Key olan bir kolonu silmek için dropForeign(['kolon_adi']) metodu kullanılabilir.
    $table->dropForeign(['user_id']);
  5. Migration sırasında rearrange yapmak için after('column_name') diyebilirsin. 
    $table->string('name')->after('city');

    buradaki after() metodunun sıralama önemli... sütunu tanımladıktan sonra hemen after() metodunu koymamız lazım.

    $table->foreignId('goal_id')->after('date')->nullable()->constrained();
  6. Factory seeder ile migration'ı sıfırdan oluştur. 
    php artisan migrate:fresh --seed
  7. Migration Sırasında İçerik eklemek 
    public function up()
    {
       Schema::create('roles',  function(Blueprint $table) {
          $table->id();
          $table->string('name');
          $table->timestamps();
       });
    
       $roles = ['User', 'Administrator', 'Publisher'];
       foreach($roles as $role) {
          Role::create(['name' => $role]);
       }
    }

Validation

  1. Form validation'ı göstermesi hepsiberaber
    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
  2. Ayrı ayrı 
    <div class="mt-3">
        <label class="mb-0 font-weight-bold" for="">Profil Adınız:</label>
        <input class="form-control" type="text" name="alias" placeholder="ör. crazyboy89" value="{{ old('alias') }}" required>
        @error('alias')
        <div class="alert alert-danger">{{ $message }}</div>
        @enderror
    </div>
  3. Validation'ı post controllerda hızlıca yapmak istersek 
    request()->validate(['email' => 'required|email']);
    $user->email = request('email');
    
    redirect('/')->with('success', 'Email saved');

    şeklinde yapabilirim.

Routes

  1. Terminalden bütün route listeni görmek istersen php artisan route:list komutunu çalıştırabilirsin.
  2. Bu komut gereğinden fazla bilgi veriyorsa sana o zaman bunların içinden dilediklerini görmek için 
    php artisan route:list --columns=action,uri,name

    gibi bir komut kullanabilirsin.

  3. Resource routeları kullanmak routes dosyasını daha okunaklı kılar. Bir controller oluştururken onun bir resource controllerı olacağını belirtebilirsin. Hatta hangi modele bağlı olduğunu da yazabilirsin. 
    php artisan make:controller PhotoController --resource

    veya belli bir modele bağlamak istersen

    php artisan make:controller PhotoController --resource --model=Photo

    hatta request dosyalarını da aynı anda hazırlamak istersen 

    php artisan make:controller PhotoController --resource --model=Photo --requests
  4. Bunları yaptıktan sonra routes dosyasında 
    use App\Http\Controllers\PhotoController;
    
    Route::resource('photos', PhotoController::class)->only(['index', 'show']);
    // veya
    Route::resource('photos', PhotoController::class)->except(['create', 'store', 'update', 'destroy']);
  5. Eğer Laravel 8'de tavsiye edilen şekilde routeları yazıp, sınıflarını import ediyorsan o zaman RouteServiceProvider.php dosyasında namespace satırını silmemiz gerekiyor.
    protected function mapWebRoutes()
    {
        Route::middleware('web')
            //->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    }
  6. Routelara ayrı ayrı middleware kontrolü koyabilirim. 
    Route::resource('articles', ArticleController::class)->middleware('auth');

    ama tek tek farklı routelar için yapmak yerine bu nevi bir middleware'e ihtiyaç duyacak routeları grup içine alıp, o gruba toptan middleware uygulayabilirim. 

    Route::group(['middleware' => 'auth'], function() {
       Route::resource('articles', ArticleController::class);
    });
  7. Grup içinde grupta tabii ki yapabilirim. 
    Route::group(['middleware' => 'auth'], function() {
       Route::resource('articles', ArticleController::class);
    
       // Admin routes
       Route::group(['middleware' => 'is_admin'], function() {
          Route::resource('categories', CategoryController::class);
       })
    });

Exception Handling

  1. Exception handling için exception'ının olup olmadığını öncelikle try/catch ile yakalamam lazım. 
    try {
        $response = $mailchimp->lists->addListMember('de213', [
            'email_address' => request('email'),
            'status' => 'subscribed'
        ]);
    } catch (\Exception $e) {
        throw ValidationException::withMessages([
            'email' => 'This email could not be added to our list',
        ]);
    }
  2. Throw dediğin exception'ı nasıl gösterecek? @error ile... 
    @error('email')
    {{ $message }}
    @enderror

Eloquent Update

  1. Var olan bir nesne üzerinde update yaparken 
    public function update(Request $request, Article $article)
    {
       $data = $request->all();
       $data['published_at'] = $request->input('published) ? now() : null;
       $article->update($data);
    
       return redirect()->route('articles.index');
    }

Eloquent'ta Yüklü İşlem Yaparken

  1. Eloquent'te get() all() ile bütün veriyi çekip yüklü operasyon yapmamız gereken noktalarda chunk kullanılabilir. chunk() sayesinde belli bir sayıda veriyi işleyip, onlar bittikten sonra yeni bir küme alarak operasyonları yürütebiliriz. 
    Step::chunk(200, function ($steps) {
        foreach ($steps as $step) {
            $step->user_id = $step->body->user->id;
            $step->save();
        }
    });
  2. Daha da performans gerektiren işlem için cursor kullanılabilir.

Authentication - Kullanıcı Şifre Güncellemesi

  1. Kullanıcı şifre güncellemesi yaptığımız bir ekranımız olduğunu varsayalım. Kişinin yeni şifre kaydetmesi için eski şifresini de yazması gerektiği bir kurgumuz var. Eski diye yazılan şifrenin veritabanındaki kullanıcı şifresi olup olmadığını kontrol için Hash::check() metodunu kullanabiliriz. 
    if (Hash::check($request->password, $user->password)) {
       $user->password = Hash::make($request->newpassword);
       $user->save();
    }

Form Submitting: Checkbox

  1. Formumuzda bir checkbox var 
    <input type="checkbox" name="published" value="1" /> Published

    Bunu True/false olarak işlemek için: 

    Article::create($request->all() + [
       'user_id' => auth()->id(),
       'published_at' => $request->input('published) ? now() : null
    ]);

Form Submitting: Extra alanlı Create

  1. X bir model için formdan gelen bütün dataları kullanarak hızlıca bir girdi oluşturmak ve hatta formda olmayan ek bir bilgiyi de modele yüklemek istersek aşağıdaki gibi diyebiliriz.
    Article::create($request->all() + ['user_id' => auth()->id()]);

Model'e Global Scope Bağlamak

  1. Örneğin Makale modelimiz var ve her makale bir kullanıcı tarafından yazılıyor. Makaleye giren kullanıcı sadece kendi makalelerini görsün istiyorum. Bunu controller'da 
    Article::where('user_id', auth()->id())->get();

    diyerek yapabilirim. Ama Controller içinde farklı farklı birçok/her fonksiyonda işlem yapmadan önce özellikle bu kontrole ihtiyacım oluyorsa, bu kontrolü modelin içine Global Scope olarak ta atayabilirim. Article Model'inde 

    use Illuminate\Database\Eloquent\Builder;
    ...
    protected static function booted()
    {
       if (auth()->check()) {
          static::addGlobalScope('user', function(Builder $builder) {
             $builder->where('user_id', auth()->id());
          });
       }
    }

    ayrıca kullanıcı admin değilse sadece kendi makalesini görsün, yoksa bütün makaleleri görebilsin dersek: 

    use Illuminate\Database\Eloquent\Builder;
    ...
    protected static function booted()
    {
       if (auth()->check() && !auth()->user()->is_admin) {
          static::addGlobalScope('user', function(Builder $builder) {
             $builder->where('user_id', auth()->id());
          });
       }
    }

Accessors & Mutators

  1. Accessors & Mutators veritabanında modelin bir özelliğini daha manipüle ederek görmemizi sağlar. Vue'daki computed property gibi. Bunu modelde belirtiriz. Ve Laravel'de şu şekilde yazılmalıdır get + PropName + Attribute. Bu şekilde yazdıktan sonra mesela 
    public function getIsAdminAttribute()
    {
       return $this->role_id == 2;
    }

    Aslında is_admin diye bir attribute'um yok ama bunu daha sonra template'te sanki attribute gibi kullanıp, kontrol sağlayabiliyorum. 

    @if(auth()->user()->is_admin)
    <input type="checkbox" name="published" value="1" 
       @if($article->published_at) checked @endif /> Published
    @endif

Referanslar

  1. Laravel Docs - Controllers, Resource Controllers - link