Laravel 5 ile CMS - Migration, Seed, Middleware, Elixir, Bower, Gulp, Blade

PHP
Kurulumu yaptığımıza göre uygulamaya başlayabiliriz. Bu kısımda, kullanıcıların içerik yönetim sisteminin, yönetici(admin) paneline giriş çıkış yapabilmelerini sağlayacak olan kısmı, yani Authentication'ı tamamlayacağız.

Öncelikle Laravel kurulumundan sonra karşınıza çıkan klasörler ilk bakışta sizi korkutabilir, ancak ilerledikçe daha rahat edeceksiniz. Çok basit bir şekilde açıklayacak olursam, uğraşacağımız klasör genellikle app klasörü olacak ve CMS uygulaması geliştirdiğimiz için bol bol CRUD(Create-Read-Update-Delete) operasyonuyla uğraşacağız. Genellikle de uygulamaya yeni bir şey ekleyeceğimizde, app klasörünün içerisindeki Http klasörüyle ilgileneceğiz. Yine herhangi bir framework'un en önemli kısmı olan routes da yine bu klasörde. Diğer klasörlerden bootstrap klasörü uygulamanın çalışmasını sağlayan, pek uğraşmayacağımız bir klasör iken, config klasörü her türlü ayarı yapacağımız klasördür. database klasöründe de veritabanı ile ilişki kurarken kullanacağımız migration ve seedleri oluşturacağız. public klasörü ise her türlü asset yani css ve javascript dosyalarının bulunduğu klasörken, resources'ta view dosyaları ve çeşitli dil yani multilanguage desteği sağlayan kısımlar bulunmakta. storage'ta ise Laravel'e has Blade temaları, sessionlar, cache vb. gibi dosyalar yer alırken, test klasörü de yapılacak testlerin tutulduğu klasör olmakla beraber vendor klasörü de composer ile uygulamamızda kullandığımız, otomatik yüklenecek parçaların yer aldığı klasör.

Başlamadan önce, Netbeans, PhpStorm veya Sublime Text 2 gibi bir IDE kullanıyorsanız bunlarda işimizi kolaylaştıracak olan bir araç mevcut. PhpStorm vb. IDE'ler Laravel'in modüllerini tanıyamıyor ve dolayısıyla da otomatik tamamlama gibi bir IDE'yi güzel kılan özelliklerden yararlanamıyorsunuz. Bu yüzden de bunun için geliştirilmiş olan bir aracı kullanacağız. Projenizin bulunduğu klasörde terminalde aşağıdaki komutu yazın:
wget https://gist.githubusercontent.com/barryvdh/5227822/raw/d565a1fabd5769ad2ad448b2380b6f2af366dc8e/_ide_helper.php
Bunu yazdığınızda, PhpStorm ya da Netbeans gibi bir IDE'nin artık Laravel modüllerini tanıdığını göreceksiniz.

İlk bakışta, bazı şeyleri daha anlamlı kılmak için app/Http/routes.php dosyasını açarsanız, alttaki kısmın en başta default olarak geldiğini göreceksiniz:
Route::get('/', 'WelcomeController@index');
Route::get('home', 'HomeController@index');
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
Burada, / işareti root yani anasayfa olarak uygulamada kullanılan yeri belirtiyor ve root'a HTTP/GET isteği geldiğinde, WelcomeController'ın index yönteminin çağrılacağını belirtiyor. Aynı şekilde /home yazdığınızda da HomeController'ın index yönteminin çağrılacağı belirtiliyor. Controllers kısmında da implicit routing olarak geçen, o controllerın içindeki yöntemleri otomatik olarak routing içerisine ekleyen kısım ki buna daha sonra değineceğimden şimdilik bazı şeyleri karmaşıklaştırmak istemiyorum. Ancak merak ediyorsanız php artisan route:list yazarak bunların oluşturduğu routeları görebilirsiniz.

Root routingini sağlayan app/Http/Controllers/WelcomeController.php dosyasını açarsanız, alttaki kod parçasını göreceksiniz. Bu kod parçası da resources/views/welcome.blade.php dosyasını yüklüyor. Buradaki blade eki de Laravel'in kendi templating bileşeni.
public function index()
{
    return view('welcome');
}
Eğer bu kısmı alttaki gibi değiştirir ve anasayfanızı tekrar kontrol ederseniz, Anasayfa yazdığını göreceksiniz.
public function index()
{
    return 'Anasayfa';
}
Laravel, veritabanı konusunda SQLite, MySQL, PostgreSQL ve Microsoft SQL Server'ı destekliyor. Ben tercihen MySQL üzerinden anlatacağım ancak çok bir şey farketmiyor. Eğer örneğin SQLite ile devam etmek istiyorsanız, config/database.php içerisinde default'u sqlite olarak değiştirin ve terminalden alttaki komut ile basit bir SQLite veritabanı oluşturun.
touch resources/database.sqlite
MySQL ile devam ediyorsanız, projenizde bulunan, .env dosyasını açın ve sırasıyla kendi veritabanınza göre DB_HOST, DB_DATABASE, DB_USERNAME ve DB_PASSWORD değişkenlerini değiştirin. Burada .env gibi bir dosya kullanılmasının sebebi, php dosyalarında bu değişkenlerin direkt olarak yazılmamasından kaynaklanmaktadır. Örneğin bu projeyi herhangi bir git repository'sinde barındırdığınızı düşünün ve bunun herkese açık olduğunu düşünün, herhangi bir kişi bu verileri görebilir. Şimdi aklınıza şu soru da takılabilir, neden kendi projemi herhangi bir git repository'sinde barındırayım, burada belirtmem gerekir ki, muhtemelen daha önceden birçok kez yaptığınız Filezilla ya da herhangi bir FTP client'ı ile yaptığınız sürekle ve bırak yöntemi günümüzde pek kullanılmamakta. Farkedebileceğiniz üzere herhangi bir dosyayı değiştirdiğinizde, versiyon kontrolünün işe yaraması lazım ve sunucunuza da dosyaları atarken git aracılığıyla atmanız lazım ki böylece hangi dosyayı değiştirdiğinizi aklınızda tutmak zorunda kalmayın, en önemlisi de her şeyi otomatik hale getirebilin ki daha çok vakit kazanın. Her neyse bu kısa ama önemli olduğunu düşündüğüm kısımdan sonra Laravel migrationlarına başlayabiliriz.

Migration'ın ne olduğunu da açıklayacak olursam, veritabanınızda herhangi bir şeyi oluşturmak veya düzenlerken, phpmyadmin gibi araçları kullanmaktansa, her şeyi daha hızlı oluşturup, değiştirebilmenizi sağlayan, birçok framework'te bulunan, bana göre en önemli bileşenlerden birisidir. Şimdi yine neden böyle yapayım ki diyebilirsiniz, size belirtmem lazım ki, manuel yaptığınız her şey size sadece zaman kaybettirir ve düzeninizi sağlayamazsınız, bazı şeyleri unutabilirsiniz. Migrationlar sayesinde hem bu düzeni sağlayabilir, hem de belirli bir yapıyı daha iyi oluşturabilirsiniz, en önemlisi de, yine üstte bahsettiğim, projenizi production yani sunucuya attığınızda, herhangi bir değişiklik yapacağınızda sunucunuzun kontrol paneline girip, yine phpmyadmin gibi bir aracı kullanmak zorunda kalmazsınız.

database/migrations klasörüne bakarsanız, iki tane php dosyası göreceksiniz. Bunlar default olarak gelen, iki migration dosyası, örneğin 2014_10_12_000000_create_users_table.php dosyasını açarsanız karşınzıda şöyle bir şey göreceksiniz.
class CreateUsersTable extends Migration {

    public function up()
    {
        Schema::create('users', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password', 60);
            $table->rememberToken();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::drop('users');
    }

}
up fonksiyonu, migration'ı çalıştırdığımızda bizim için oluşturacağı sütunlarını göstermekteyken, down ise o tabloyu yok edecek olan kısımdır. Burada, increments('id'), genellikle her tabloda bulunan auto_increment integer id alanını oluştururken, string kısmı da daha önceden sıklıkla kullandığınızı düşündüğüm varchar sütunlarını oluşturmaktadır, unique kısmı da tahmin edebileceğiniz üzere unique key'i eklemekte, timestamps ise otomatik olarak created_at ve updated_at datetime'larını oluşturmaktadır. rememberToken yöntemi de aslında 100 uzunluklu bir varchar alanı olup, Authentication'da beni hatırla için kullanılan yardımcı bir metodtur. Örneğin password'un yanındaki 60 da, o alanın maksimum uzunluğunu belirtmektedir. Bu kısımda değiştireceğimiz herhangi bir şey olmadığı için, bir ekleme çıkarma yapmayacağız. Bunları veritabanımıza eklemek için terminalde:
php artisan migrate
Bu da size alttaki çıktıyı verecek:
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
Burada ufak bir bilgi, artisan komutlarını unutabilirsiniz, yapmanız gereken tek şey terminalde alttaki komutu yazmak, bu size tüm komutları gösterecektir.
php artisan list
Ya da özel bir komut ile ilgili özel yardım almak isterseniz, örnek durum olarak da migrate komutunu seçerseniz de, alttaki gibi bir komut yazmanız yeterli olacaktır.
php artisan help migrate
Tekrar migration'a geri dönecek olursak, örneğin bir migration'ı yanlışlıkla yaptınız ve geri almak istiyorsunuz, o zaman da, php artisan list ile görmüş olabileceğiniz, alttaki komutu kullanabilirsiniz.
php artisan migrate:rollback
Bunun dışında, örneğin kategoriler için yeni bir migration oluşturmak için alttaki komutu kullanabilirsiniz, --create içerisindeki kısım tablonun adını belirtmekteyken create_categories_table dosyanın adını belirtmektedir.
php artisan make:migration create_categories_table --create="categories"
Bunu çağırdınızda alttaki gibi bir çıktı aldığınızı göreceksiniz.
class CreateCategoriesTable extends Migration {

    public function up()
    {
        Schema::create('categories', function(Blueprint $table)
        {
            $table->increments('id');
            $table->timestamps();
        });
    }
public function down() { Schema::drop('categories'); } }
Son olarak da başka sık kullanabileceğiniz özellik ise tablonuza yeni sütun eklemek olabilir. Onun için de, yine kategoriler için bir örnek verecek olursam:
php artisan make:migration add_slug_to_categories_table --table="categories"
Tüm bunları da en üstteki gibi php artisan migrate ile veritabanına aktarabilirsiniz. Hangi dosyaları migrate edip etmediğinizi unuttuysanız da php artisan migrate:status yazarak basit bir tabloda görebilirsiniz. Sanıyorum ki migration kısmını anlamışsınızdır, kategoriler için oluşturduğumuz migration dosyalarını silebilirsiniz, ileride o kısma tekrar döneceğiz. Migration hakkında daha fazla detay için Laravel dökümantasyonlarına bakabilirsiniz.

Authentication modülü, Laravel'i yüklediğinizde aslında otomatik olarak geliyor, ancak tabii ki neyin ne olduğunu anlayabilmemiz için direkt olarak bunu kullanmayacağız. Ancak yine de merak ediyorsanız, ve kurulumdaki gibi php -S localhost:8000 -t public komutu ile sunucuyu başlattıysanız, http://localhost:8000/auth/register girerek kendinizi kaydedebilir, daha sonrasında ise http://localhost:8000/auth/login adresinden giriş yapabilir http://localhost:8000/auth/logout adresinden de çıkış yapabilirsiniz, ancak işin içindeki mantığı pek anlamadan direkt olarak bunları kullanmak çok sağlıklı değil. Buradaki mantığı anlayabilmek için, öncelikle app/Http/Controllers/Auth/AuthController dosyasını açmanız lazım, alttaki gibi bir kod parçasıyla karşılaşacaksınız.
class AuthController extends Controller {
use AuthenticatesAndRegistersUsers;
public function __construct(Guard $auth, Registrar $registrar) { $this->auth = $auth; $this->registrar = $registrar; $this->middleware('guest', ['except' => 'getLogout']); } }
Burada ilk bakışta çok anlam veremediğiniz şeylerin olduğunu biliyorum, ancak çok detaya girmeden anlatacak olursam, Guard ve Registrar'ın önceden tanımlanmış birer interface olduğunu ve içerisinde aslında bizim sıfırdan uğraşacak olsak, baya vaktimizi alacak olan Authentication modülünü barındırdığını görebilirsiniz. Bunların her biri Laravel'in Illuminate Auth modülü içerisinde tanımlı, eğer modern bir IDE kullanıyorsanız, Guard ve Registrar'ın üstüne CTRL + Click yaparsanız içeriklerini görebilirsiniz. Benim burada bahsetmek istediğim şey ise buradaki middleware kısmı. Daha önceden herhangi bir framework ile uğraştıysanız, muhtemelen admin ve arayüz controllerları olarak iki ana controller oluşturmuş, diğer controllerlarınızı da bunlar üzerinden genişletmişsinizdir(extend), admin controllerınızın içinde de, kullanıcının authenticated olduğunu kontrol edip, ona göre kullanıcıyı giriş sayfasına yönlendirmiş, böylece her bir controller içerisinde bunu kontrol etmektense, tek bir base admin controllerıyla admin panelinizi yetkili olmayan kullanıcılara karşı korumuşsunuzdur. Eğer bunu anlamadıysanız alttaki kod parçasına bakarak, anlatmak istediğimi anlayabilirsiniz.
class AdminController{

    function __construct()
    {
        if(!$this->user->loggedin())
        {
            redirect('url');
        }
    }

}

class ArticleController extends AdminController{}
Bu yöntem, şu ana kadar hep işinizi görmüş olabilir, ancak katmanların herbirinin ayrı olması gerektiği için, bunun kontrolünün controller içerisinde yapılmaması gerekiyor, bu yüzden de middleware olarak tanımlanan, birçok frameworkte bulunan bu modülün varlığı gerekli oluyor. app/Http/Middleware/Authenticate'i açarsanız alttaki gibi bir kod parçasıyla karşılaşacaksınız.
public function handle($request, Closure $next)
{
    if ($this->auth->guest())
    {
	if ($request->ajax())
	{
	    return response('Unauthorized.', 401);
	}
	else
	{
	    return redirect()->guest('auth/login');
	}
    }
    return $next($request);
}
Burası, belki de bu yazının Laravel'in middlewareler yardımıyla kullanıcının authenticated olup olmadığını nasıl anladığıyla ilgili en önemli kısım. Eğer kullanıcı giriş yapmamış ve auth middleware'i ile çalışan bir yere ulaşmaya çalışıyorsa, gelen isteğe göre ona geri dönüş yapıyor, ve en önemlisi de, bunu kontrol ettikten sonra iş akışı devam ediyor. En altta gördüğünüz return $next($request) kısmı, Laravel'in pipeline'a(kaba tabirle gerçekleşmesi planlanan işleri barındıran bir akış) yani görevlerin işleyişine devam edip, diğer işlerine devam etmesini sağlıyor. Eğer bu kısmı silerseniz, Laravel kullanıcının giriş yapıp yapmadığını kontrol ettikten sonra kendini sonlandıracaktır çünkü siz, pipeline'ı kırıp, iş akışını bozmuş olursunuz. O yüzden herhangi bir yeni middleware tasarlarken, bu kısmı mutlaka ve mutlaka kodunuzda bulundurmalısınız. Peki bu middleware'i Laravel nasıl tanıyor, bu sorunun cevabı için de app/Http/Kernel.php dosyasına bakmalısınız.
protected $middleware = [
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'App\Http\Middleware\VerifyCsrfToken',
];

protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];
Burada direkt olarak middleware olarak tanımlanan kısım global, uygulamanın her aşamasında kontrol edilen middlewareleri barındırıyor, örneğin maintenance modunu inceleyecek olursak, php artisan down yazar ve tarayıcıda sayfayı yenilerseniz göreceksiniz ki hiçbir sayfaya ulaşamıyorsunuz ve Laravel size sitenin bakımda olduğunu belirtiyor, işte bu kontrolü yapan global middleware Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode, uygulamanın iş akışında öncelikle bu middlewarei kontrol ediyor ve uygulama down ise direkt olarak bunu döndürüyor, neden önemli olduğuna gelirsek, en başta anlattığım gibi, bunu base controller'da eğer bakım modunda değilse devam et şeklinde belirtmektense, katmanları ayırarak bu şekilde uygulamayı inşaa etmek çok daha mantıklı ( bu arada uygulamanızı da bakım modundan çıkarmak için php artisan up yazmanız lazım). routeMiddleware kısmı da uygulamanın kendine has middlewarelerini barındırıyor. Örneğin admin ya da editor diye iki katman oluşturup, bunları bir middleware ile tanımlayacaksınız, örneğin admin kısmının her kısma ulaşabilmesini sağlayacakken, editör katmanının bazı kısımlara erişimini kısıtlayacaksanız, işte bu ve bunun gibi örneklerde bu middlewareleri routeMiddleware içinde belirtip Laravel'e tanıtmanız lazım. Uygulamada da auth middleware'i ile kullanıcının giriş yapıp yapmadığını kontrol ederken, guest middlewarei ile de giriş yapmış kullanıcıların şifremi unuttum ya da giriş sayfası gibi görmemeleri gereken sayfalardan yönlendirilmesi sağlanıyor. Şimdi geri dönüp, app/Http/Controllers/HomeController.php ve app/Http/Controllers/WelcomeController.php dosyalarını açarsanız ikisinde de middlewareleri görebilir ve ne yaptıklarını tahmin edebilirsiniz. Eğer tahmin etmekte biraz güçlük yaşadıysanız, HomeController'a authenticated, yani giriş yapmış kişiler ulaşabilecekken, WelcomeController'a sadece giriş yapmamış kişiler erişebilecek ve bu middlewareler bu işlemde bize yardımcı olacak, teker teker her bir yöntemin içerisinde bunu kontrol etmek zorunda kalmayacağız.

Daha önceden de belirttiğim gibi, biz ufak bir içerik yönetim sistemi oluşturduğumuz için, otomatik gelen Authentication modülünü kullanabiliriz, auth middlewareini de routing içerisinde bu yazının sonlarında admin kısmı için kullanacağız. resources/views/app.blade.php ve resources/views/home.blade.php dosyalarını da yine silebilirsiniz, incelemenize de gerek yok, şimdi o kısma giriş yapacağız. Giriş olarak şunu belirteyim, Laravel controller yöntemleri için view ararken klasör yapısına göre arama yapıyor, örneğin Controllers klasörü içerisinde Home controllerının index yöntemi için, resources/views/home/index.blade.php dosyasını arıyor ya da admin klasörü içerisindeki dashboard controllerının index yöntemi için view ararken, resources/views/admin/dashboard/index.blade.php dosyasını arıyor. Blade'i birazdan detaylı inceleyeceğiz, ama öncelikle belirtmeliyim ki nasıl ki aynı şeyleri tekrar tekrar yazmak istemiyor ve kodumuzu temiz tutmayı hedefliyorsak, aynısını da view dosyaların da yapmamız gerekiyor. Bu yüzden de her seferinde html tagi ya da body tagi açıp blade dosyalarını işlevsiz kılmaktansa, her bir view dosyasını, nasıl ki controllerı extend edebiliyorsak, ana bir view dosyası üzerinden oluşturacağız. Bu yüzden resources/views içerisinde layouts diye bir klasör oluşturup, application.blade.php ve admin.blade.php adlı iki temel layout dosyası oluşturuyoruz. application.blade.php dosyasıyla yine şimdi pek uğraşmayacağız, dediğim gibi, öncelikli olarak işimiz panelimizle olduğundan admin.blade.php dosyası önceliğimiz. Ancak bu dosyaya dönmeden önce yine uğraşmamız gereken başka bir kısım var ki o da asset management yani css ve stil dosyaları gibi uygulamamızda kullanacağımız dosyaların yönetimi. Burada isterseniz her şeyi kendiniz indirip public içerisinde barındırabilirsiniz, ama bu pek uygun bir yöntem değil, belirttiğim gibi, önemli olan şey her şeyi versiyon kontrolünde bulundurmamız, buna css ve javascript dosyaları da dahil, dolayısıyla en başta bahsettiğim bower dosyalarıyla css ve javascript dosyalarımızı idare edecekken, Gulp yardımıyla Laravel'in Elixir parçasıyla da bunları minimize edip, efektik bir biçimde kullanabileceğiz, böylece uygulamamız daha hızlı çalışabilirken, idare etmesi de kolay olacak.

Öncelikle gulp ve bower'ın sisteminizde yüklü olması lazım, onları yükleyebilmeniz için de node'un yüklü olması lazım, sırasıyla
sudo apt-get install nodejs
sudo apt-get install npm
sudo npm install --global gulp bower
Laravel dosyalarının bulunduğu klasörde de elixir ve onun çalışması için gerekli olan paketleri yüklemek için:
sudo npm install
Şimdi bunu yüklediğimize göre, Bower ayarlarını yapmamız lazım. bower.json dosyamızın içeriği alttaki gibi olacak, yükleyeceğimiz paketler dependencies içerisinde. Ayrıca resources/assets/less içerisindeki bootstrap klasörünü silebilirsiniz.
{
"name": "laravel-5-simple-cms",
"version": "0.0.0",
"homepage": "https://github.com/ozdemirburak/laravel-5-simple-cms",
"license": "MIT",
"private": true,
"dependencies": {
"jquery": "~1.11.2",
"admin-lte": "~2.0.5",
"font-awesome": "~4.3.0",
"datatables": "~1.10.6",
"datatables-bootstrap3": "*",
"mjolnic-bootstrap-colorpicker": "~2.1.1",
"bootstrap-datepicker": "~1.4.0",
"select2": "~3.5.2",
"select2-bootstrap-css": "~1.2.5"
}
}
Ayrıca bower'a bu paketleri hangi klasöre yükleyeceğini belirtmemiz lazım, bunun için de .bowerrc dosyasının içeriğini alttaki gibi oluşturmamız lazım.
{
"directory": "resources/assets/vendor"
}
Ve son olarak üstteki paketleri resources/assets/vendor içerisine yüklemek için, terminalde:
bower install
Assetler yüklendiğinde bunları Elixir yardımıyla Gulp'u kullanarak tüm assetleri derleyebileceğiz. Bu arada ben kendime göre less klasörünün içerisindeki app.less dosyasını application.less olarak adlandırdım, aynı zamanda da admin.less diye bir dosya oluşturdum. Yine javascript dosyalarını da derlemek için resourcess/assets/ içerisinde js diye de bir klasör oluşturup, içerisinde admin.js ve application.js olarak iki farklı dosya oluşturdum. Daha sonra gulpfile.js dosyasını alttaki gibi düzenleyin.
var elixir = require('laravel-elixir');

var bowerDir = './resources/assets/vendor/';

var adminLess = [
bowerDir + 'admin-lte/build/less',
bowerDir + 'bootstrap-datepicker/less',
bowerDir + 'font-awesome/less',
];

var adminCss = [
'bootstrap/dist/css/bootstrap.min.css',
'admin.css',
'select2/select2.css',
'select2-bootstrap-css/select2-bootstrap.css',
'mjolnic-bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css',
'datatables/media/css/jquery.dataTables.min.css',
'datatables-bootstrap3/BS3/assets/css/datatables.css',
'admin-lte/dist/css/skins/skin-blue.min.css'
];

var adminJs = [
'jquery/dist/jquery.min.js',
'bootstrap/dist/js/bootstrap.min.js',
'bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js',
'mjolnic-bootstrap-colorpicker/dist/js/bootstrap-colorpicker.min.js',
'datatables/media/js/jquery.dataTables.min.js',
'datatables-bootstrap3/BS3/assets/js/datatables.js',
'select2/select2.min.js',
'admin-lte/dist/js/app.min.js'
];

elixir(function(mix) {
mix.less('admin.less', bowerDir, { paths: adminLess })
.styles(adminCss, 'public/css/admin.css', bowerDir)
.scripts(adminJs, 'public/js/admin.js', bowerDir)
.version(['css/admin.css', 'js/admin.js'])
.copy('resources/assets/js/admin.js', 'public/js/admin-custom.js')
.copy('resources/assets/js/application.js', 'public/js/application-custom.js')
.copy(bowerDir + 'font-awesome/fonts', 'public/build/fonts')
.copy(bowerDir + 'datatables/media/images/*.png', 'public/build/images')
.copy(bowerDir + 'mjolnic-bootstrap-colorpicker/dist/img/bootstrap-colorpicker/*.png', 'public/build/img')
.copy(bowerDir + 'select2/*.png', 'public/js')
;
});
Peki nedir bu Gulp diye soracak olursanız, birçok modern uygulamada kullanılan, bazı görevleri, ki genellikle bu görevler assetler yani css, javascript, sass, less, coffee gibi çeşitli uzantılara sahip dosyalarla ilgili, hızlı bir şekilde gerçekleştirmek için oluşturulmuş önemli bir javascript kütüphanesi olduğunu söyleyebilirim. Gulp ile biraz önce bahsettiğim uzantılara sahip dosyalarınızı birleştirebilir, minimize edebilir veya takip edebilirsiniz. Unutmayın ki en büyük amacımız her şeyi otomatik hale getirmek, hiçbir şekilde eskisi gibi copy paste ya da çeşitli online toollar ile uğraşmak istemediğimiz için, Gulp kullanımı da uygulama için önemli. Burada da Laravel'in Gulp görevleri için oluşturulmuş Elixir modülü(API) yardımıyla tüm bu işlemleri daha pratik şekilde yapabiliyoruz. Peki bu kod parçası napıyor diye merak ediyorsanız, bower ile yüklediğimiz ve vendor'da bulunan tüm assetleri alıp, birleştirip, Laravel'in public kısmına taşıyor, biraz inceleyince aslında her şeyin çok açık olduğunu göreceksiniz. Aynı zamanda bu kütüphanelerde kullanılan resim, font gibi kısımları da build klasörüne kopyalıyoruz ki her şey düzgün olsun.

Bunu işleme koymadan önce CSS dosyalarını referans etmek için, admin.less dosyasını da alttaki gibi düzenleyebilirsiniz, onun dışında authentication kısmı için de birkaç ekstra stil de bulunuyor, dahil edip etmemek size kalmış.
@import "AdminLTE";
@import "font-awesome";
@import "datepicker3";

.validation{
button{
list-style: none;
}
span{
display: list-item;
margin-left: 10px;
}
}

.bg-black-50 {
background-color: #222222;
}

.bg-gray-50 {
background-color: #eaeaec !important;
color: #444;
}

.login-box{

.header {
background: none repeat scroll 0 0 #3d9970;
border-radius: 4px 4px 0 0;
box-shadow: 0 -3px 0 rgba(0, 0, 0, 0.2) inset;
color: #fff;
font-size: 26px;
font-weight: 300;
padding: 20px 10px;
text-align: center;
}

.body{
background: none repeat scroll 0 0 #fff;
color: #444;
padding: 10px 20px;
.fa{
margin-top: 10px;
}
}

.footer{
background: none repeat scroll 0 0 #fff;
color: #444;
padding: 10px 20px;
border-radius: 0 0 4px 4px;
a{
padding-left: 0;
}
}

}
Ve artık gulp dosyasıyla işlemleri gerçeklemek için terminalde gulp yazmanız lazım. Eğer her şeyin minimize edilmiş, debug logları(map dosyaları) çıkmamış halde oluşmasını isterseniz de gulp --production yazmanız lazım. İleride tekrar bu dosyaya dönüp bazı eklemeler yapmamız gerekecek, çünkü farkettiyseniz sadece admin kısmı için gerekli assetleri oluşturduk. Birazdan farkedeceğiniz üzere, bir sürü ayrı css ve javascript dosyasında dahil etmek yerine, tek bir admin.css ve admin.js dosyasını sistemimizde kullanacağız, tekrar belirtmek istediğim gibi, her işi kendi katmanında halletmek önemli.

Authentication için de bir layout belirlersek iyi olabilir, çünkü hem uygulama yani arayüzde hem de admin kısmına göre baya farklı. O yüzden layouts klasöründe de auth.blade.php diye bir dosya oluşturabiliriz. İçeriği de çok basit:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title> @yield('title') </title>
    <link rel="stylesheet" type="text/css" href="{{ url( elixir('css/admin.css') ) }}">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body class="bg-black-50">
<div class="wrapper">
    @yield('content')
</div>
<script src="{{ url( elixir('js/admin.js') ) }}" type="text/javascript"></script>
</body>
</html>
Şu anda ilk blade dosyasıyla karşılaştınız, direkt ilginizi çekebilecek olan şeyler yield ifadeleri. yield ile bir nevi dinamik değişken belirtiyorsunuz ve bu layoutlardan türetilecek olan her bir yeni blade dosyasında bu atamaları belirtiyorsunuz, yine ilginizi çekebilecek bir başka şey javascript ve css dosyasının referansını verirken elixir ifadesi kullanmamız. elixir ifadesi, biraz önce oluşturduğumuz javascript ve css dosyalarının direkt olarak public/build içerisindeki rev-manifest.json dosyasından referansı gönderilen assetin hangi versiyon olduğunu bulup, direkt olarak bunu kullanmamızı sağlıyor. Şimdi artık login sayfamızı düzgün bir şekle sokabiliriz. Bunun için resources/views/auth/login.blade.php dosyasını düzenleyeceğiz. Bu dosyanın zaten hazır olduğunu biliyorduk ama farkedebileceğiniz üzere çok fazla HTML parçası var ve bir framework kullanıyorsanız bu durum sizi rahatsız eder. Bunun için Laravel'in formlar için default olarak gelmeyen iki parçasını kullanacağız. Terminalden composer dosyamıza bu kısımları eklemek için alttaki kısmı yazabilirsiniz.
sudo composer require "laravelcollective/html": "~5.0"
Ancak iş sadece bununla bitmiyor, bunu dahil edeceğimizi Laravel'e belirtmemiz de lazım. config/app.php dosyasında da providers ve aliases kısımlarını bu amaçla düzenleyeceğiz. providers kısmı Laravel'in neleri include etmesi gerektiğini söyleyen kısımmış gibi düşünebilirsiniz, aliases da namespacelerin referansı, aslında namespace HERHANGI\BIR\SEY as KISALTMA şeklindeki namespace deklarasyonundaki KISALTMA yerine gelecek kısım, ne zaman ki 3. parti bir uygulama yüklediğinizde, buraya genellikle bu uygulamaların dökümantasyonlarında belirtilen bu eklemeleri yapmanız lazım.
'providers' => [
...
'Collective\Html\HtmlServiceProvider',
],

'aliases' => [
...
'Form'=> 'Collective\Html\FormFacade',
'HTML'=> 'Collective\Html\HtmlFacade',
],
Ben kişisel olarak, herhangi bir web uygulamasında, potansiyel bir çoklu dil desteği özelliği için, tüm html dosyalarında yazı tutmayı sevmiyorum, ki bu uygulamayı da aslında çoklu dil desteği ile inşaa edeceğimizden, buna da hafiften giriş yapmak istiyorum. Başlangıç olarak, default dil seçeneğini Türkçe olarak belirleyeceğinizi düşündüğüm için, config/app.php dosyasında locale değişkenini tr yapmanız lazım. Laravel dil dosyalarını resources/lang içerisinde tutuluyor. Biz de tr klasörü oluşturup içerisinde auth.php dosyasını oluşturacağız. Sadece bu örnekte mantığını anlayabilmeniz için basit bir örnek vereceğim, diğerlerini Github üzerinden takip edebilirsiniz. Örnek resources/lang/tr/auth.php dosyasının içeriği alttaki gibi olacak:
return [

"login" => [
"title" => "Giriş Yap",
"email" => "E-mail adresi",
"password" => "Şifre",
"remember" => "Beni Hatırla",
"submit" => "Giriş Yap",
"forgot" => "Şifremi Unuttum?"
],

];
Örneğin, auth.php içerisindeki login'in title karşılığına ulaşmak istiyorsak trans('auth.login.title') şeklinde ulaşmamız gerekiyor, başka bir örnek olarak email'e ulaşmak istiyorsak trans('auth.login.email') şeklinde yazmamız lazım. Bunun mantığının kolay olduğunu düşünüyorum, eğer Rails vb. bir framework ile uğraştıysanız, oradaki yaml dosyaları yerine, aynı mantıkla bu dosyaları kullanabilirsiniz. Login sayfasını da artık alttaki gibi oluşturabiliriz.
@extends('layouts.auth')

@section('title')
    {{ trans('auth.login.title') }}
@stop

@section('content')

    <div class="login-box" id="login-box">

        <div class="header">
            {{ trans('admin.title') }}
        </div>

        {!! Form::open(['method' => 'POST', 'url' => '/auth/login']) !!}

        <div class="body bg-gray-50">

            @include('errors.validation')

            <div class="form-group has-feedback">
                {!! Form::label('email', trans('auth.login.email')) !!}
                {!! Form::text('email', null, ['class' => 'form-control']) !!}
                <i class="fa fa-envelope form-control-feedback"></i>
            </div>

            <div class="form-group has-feedback">
                {!! Form::label('password', trans('auth.login.password')) !!}
                {!! Form::password('password', ['class' => 'form-control']) !!}
                <i class="fa fa-lock form-control-feedback"></i>
            </div>

            <div class="form-group">
                {!! Form::checkbox('remember', '1', true) !!} {{ trans('auth.login.remember') }}
            </div>

        </div>

        <div class="footer">
            {!! Form::submit(trans('auth.login.submit'), ['class' => 'btn bg-olive btn-block btn-flat']) !!}
            <a class="btn btn-link" href="{{ url('/password/email') }}">{{ trans('auth.login.forgot') }}</a>
        </div>

        {!!  Form::close() !!}
    </div>

@endsection
En başından bakarsak, extends ile başlayan kısım, o layoutu baz aldığımızı ve onu kullandığımızı belirtiyor, noktalı notasyon da views/layouts/auth.blade.php dosyasını referans ettiğini belirtiyor. Gördüğünüz üzere, yield ile belirttiğimiz kısımları da section sekmesi altında genişletebiliyoruz. Bir diğer dikkatinizi çekebilecek özellik {!! fonksiyon() !!} şeklindeki notasyon. Bu aslında bildiğiniz ile aynı, bu notasyona sıklıkla rastlayacaksınız, bir diğer notasyon şekli de {{ fonksiyon() }}, bu ikisinin arasında da önemli bir fark var, ünlemle belirtilen notasyonda HTML, Javascript vb. XSS açığı oluşturabilecek olan şeyler escape edilmiyorken, ünlemsiz notasyonda bunlar escape ediliyor, o yüzden buna göre karar vermeniz gereken kısımlar olabilir, veritabanından gelen değere güveniyorsanız rahatlıkla ünlemli notasyonu kullanabilirsiniz, ama sıkıntı olabileceğini düşünüyorsanız ve klasik örnekteki alert('XSS') gibi kötü bir tecrübe yaşamak istemiyorsanız, ünlemsiz versiyonu kullanmanız gerekir. Son olarak da @include şeklinde başka kısımları dahil edebiliyorsunuz. Mesela her bir formun validasyon kısmı ortak olacağı için, ben bunu errors klasörü altında validation.blade.php şeklinde bir dosya oluşturarak oradan bunu dahil ediyorum ki böylece her yerde sürekli aynı şeyleri yazmak zorunda kalmayayım. O dosyanın içeriği de alttaki şekilde:
@if ($errors->any())
    <div class="alert alert-danger validation">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        @foreach ($errors->all() as $error)
            <span>{{ $error }}</span>
        @endforeach
    </div>
@endif
Şimdi tekrar dikkatinizi çeken bir şey olması gerekiyor, @if ya da @foreach şeklinde şeyler nasıl oluyor? İşte yukarıda bazı temellerini açıkladığım Laravel'in template engine'i olan Blade ile PHP'de yaptığınız if, foreach vb. ifadeleri, bu şekilde belirtebiliyorsunuz, isterseniz yine yazın, tercih size kalmış, ama Blade'e özgün şekilde ilerlemek, bana göre daha mantıklı ve daha temiz, böylece tüm HTML sayfalarınızı notasyonlarıyla kaplamak zorunda kalmıyorsunuz. Eğer benle paralel ilerlediyseniz, şu anda giriş sayfanızın gayet güzel görünüyor olması lazım. Authentication'da register kısmını silmemiz lazım, sonuçta admin paneline birisinin direkt üye olarak erişebilmesini istemeyiz. Bunun için View dosyalarından auth/register.blade.php'yi başlangıç olarak silebilir, daha sonra da Http/Controllers/Auth/AuthController'ı alttaki gibi düzenleyebilirsiniz. Yaptığım şey, Registrar traitini kaldırmak oldu ve bir de normalde home'a yönlendireceğine admine yönlendirmesini istediğimizi belirttik.

use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

class AuthController extends Controller {

use AuthenticatesAndRegistersUsers;

protected $redirectTo = '/admin';

public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->middleware('guest', ['except' => 'getLogout']);
}

}
Son olarak da implicit olarak belirtilmiş olan AuthController'ı özelleştirebiliriz. app/Http/routes.php dosyasını alttaki gibi düzenleyebilirsiniz. Şifre kısmına daha sonra döneceğiz, ama yöntemleri nereden bildiğimi merak ediyorsanız da /vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php dosyasını incelerseniz, getLogout, getLogin, postLogin, getRegister ve postRegister olarak yöntemlerin belirlendiğini görebilirsiniz.
Route::get('/', 'HomeController@index');

Route::get('auth/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLogin'));
Route::post('auth/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLogin'));
Route::get('auth/logout', array('as' => 'login', 'uses' => 'Auth\AuthController@getLogout'));

Route::controllers([
'password' => 'Auth\PasswordController',
]);
Şu an kullanıcıyı girişini bitirebilmemiz lazım, register kısmını da sildik, bunu nasıl yapacağımızı merak ediyorsanız, burada da seed olarak geçen, veritabanına herhangi bir şeyi kaydetmeyi sağlayan modülü kullanacağız. database/seeds içerisinde DatabaseSeeder.php dosyasını göreceksiniz. Bu dosya seedleri yöneten asıl dosya, yorumlanmış olan $this->call('UserTableSeeder'); satırınının yorumunu kaldırın ve yine bu klasörün içerisinde UserTableSeeder olarak bir dosya oluşturun. Bu dosyanın içeriğini de alttaki gibi oluşturun.

use Illuminate\Database\Seeder;
use App\User as User;

class UserTableSeeder extends Seeder {

public function run()
{
DB::table('users')->delete();
User::create(['name' => 'Admin', 'email' => 'admin@admin.com', 'password' => Hash::make( 'password' )]);
}

}

Bu seedi yaptığımızda, daha önceden kullanıcı varsa veritabanında onu silecek ve admin@admin.com email adresine sahip şifresi password olan bir kullanıcı yaratacak. Şifreleri neden hashlediğimize gelirsek, hiçbir zaman hiçbir şifreyi veritabanında plain yani olduğu gibi tutmamamız lazım, her zaman şifrelenmiş bir şekilde tutmalıyız, bu yüzden de şifreyi bu şekilde oluşturuyoruz. Burada yine garip gelebilecek bir başka şey User nereden geliyor, Laravel baştan User modeli ile geliyor, app/User.php dosyasını açarsanız bunu görebilirsiniz. Ufak bir detay, fillable nedir diye merak ediyorsanız, örneğin bir kullanıcının id'sinin hiçbir şekilde kullanıcı tarafından değiştirilemiyor olması lazım, bunları korumak için, Eloquent'in bize sağladığı bu fillable özelliği, hangi alanların POST, PUT, PATCH gibi yöntemlerle değiştirilebileceğini söylüyor, kullanıcı için de ad, email ve şifre alanları bu kısmı oluşturuyor. Bu arada PATCH ile PUT'un ne olduğunu bilmeyebilirsiniz, detaylı araştırma yapmanızı öneririm, ama basitçe açıklamam gerekirse, PATCH ile genellikle bir ya da iki alan, yani kısmi update yaparken, PUT ile komple kaynak güncellemesi(update) yaparsınız, bunu bilmeniz şimdilik yeterli. Son olarak da bu seedi veritabanına aktarmamız lazım. Tahmin edebileceğiniz üzere alttaki komutlar bunun için yeterli, yalnız burada composer dump yapmamız lazım öncelikli olarak, bunun sebebi de bunu yapmamanız halinde, yeni oluşturduğumuz seed class'ı autoload edilmediği için bulunamadı hatası verecek olmasındandır.
composer dump
php artisan db:seed
Artık admin@admin.com email adresine sahip, password şifreli bir kullanıcınız bulunmakta. Hala bunu tam olarak test edebilmemiz mümkün değil, admin için de routing belirlememiz lazım. Bu da basit bir işlem. Önce çok basit bir şekilde Http/Controllers içerisinde Admin klasörünü oluşturup, bu klasörün içinde DashboardController oluşturun ve içeriğini de alttaki gibi oluşturun, çok ekstra bir şey yapmacağız bu controllerda:

use Illuminate\Routing\Controller;

class DashboardController extends Controller {

public function index()
{
return 'Admin Panel';
}

}
Son olarak da route dosyasına alttaki ufak eklemeyi yapın:
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function()
{
Route::get('/', 'Admin\DashboardController@index');
});
Burada, admin ön ekine sahip routelarda, auth middlewarenin geçerli olduğunu belirtiyoruz, ve adminin anasayfası olarak da DashboardController'ın index yöntemi ile çalıştığını belirtiyoruz. Son bir ufak düzenleme için de Http/Middleware/RedirectIfAuthenticated.php dosyasında handle yönteminde return new RedirectResponse(url('/admin')); şeklinde bir düzenleme yapmanız. Şimdi giriş yapmaya çalışırsanız karşınızda Admin Panel yazısını göreceksiniz. http://localhost:8000/auth/logout yazarak da çıkış yapabilirsiniz, süslemelerini de serinin bir sonraki kısmında yapacağız.

Yönetici Paneli - Giriş Sayfası

Bu makale sonunda, Laravel 5'te Migration ve Seeding yapmayı, Middleware'in ne olduğunu ve ne amaçla kullanıldığını, Elixir, Bower ve Gulp kullanımını, Blade'i basit bir şekilde kullanmayı anlamış olmalı, Authentication modülünü de kısmen benimle paralel giderek düzgün bir şekilde entegre etmiş olmalısınız.

Serinin bir sonraki makalesinde, kendi modellerinizi ve controllerlarınızı oluşturup, Laravel 5'te Request ile model kullanımını öğrenmiş olacaksınız.

Bu yazıda yaptıklarımızın olduğu dosyalara ulaşmak için de: https://github.com/ozdemirburak/laravel-5-simple-cms/tree/063b2e2477717b4742d052d26a2591d5730c5c07

Seriye ait tüm makaleler alttaki gibidir.
  1. Laravel 5 ile CMS - Kurulum
  2. Laravel 5 ile CMS - Migration, Seed, Middleware, Elixir, Bower, Gulp, Blade
  3. Laravel 5 ile CMS - Controller, Model, Request, Provider, Form
  4. Laravel 5 ile CMS - WYSIWYG Filemanager, Çoklu Dil, Google Analitik API
  5. Laravel 5 ile CMS - Events, Email ve Frontend
  6. Laravel 5 ile CMS - FTP veya SSH ile Aktarım (Deployment)
Github üzerinden projenin son haline ulaşmak için: https://github.com/ozdemirburak/laravel-5-simple-cms