برچسب: لاراول 5

  • حل مشکل invalid default value for created_at در لاراول

    در ادامه طرح سوالات ابتدایی لاراول ، این پست رو منتشر میکنم 🙂

    توی اولین مرحله که میخواید مایگریشن های لاراولیتونو ران کنید به این اررور احتمال داره بخورید :

     [Illuminate\Database\QueryException]
      SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'created_at' (SQL: create table `
      users` (`id` int unsigned not null auto_increment primary key, `name` varchar(255) not null, `email` varchar(255) n
      ot null, `password` varchar(60) not null, `remember_token` varchar(100) null, `created_at` timestamp default 0 not
      null, `updated_at` timestamp default 0 not null) default character set utf8 collate utf8_unicode_ci)

    این خطا بخاطر اینه که مای اس کیو ال شما مقدار صفر رو بعنوان مقدار پیشفرض تاریخ قبول نمیکنه . احتمالا شما NO_ZERO_DATE رو توی تنظیمات mysqlتون فعال کردید… اگه با ومپ کار میکنید به پوشه ی (مثلا) C:\wamp64\bin\mysql\mysql5.7.9  برید و فایل my.ini  رو باز کنید و مقادیر NO_ZERO_DATE,NO_ZERO_IN_DATE, رو سرچ بزنید و حذف کنید و mysql رو ریستارت کنید

    الان همه چی حله… php artisan migrate  رو برای تست ران کنید.

  • مفهموم و کاربرد Facade در لاراول

    با سلام مجدد ، حتما اگه با لاراول کار کرده باشید، بارها اسم facade به گوشتون خورده. اما facade واقعا چیه؟ طبق گفته ی سایت خود لاراول “فساد یک ظاهر استاتیک رو برای کلاسهایی که در کانتینر وجود دارن ایجاد میکنه”. در مورد IOC container قبلا توی این پست صحبت کردم . حتما در مورد کلاسهای استاتیک هم اطلاع دارید دیگه و قبلا در این باره هم اینجا حرف زدم.

    لاراول خودش کلی فساد داره که شما بدون اینکه شاید متوجه بشید دارید ازشون استفاده میکنید. مثلا همین Session یا Form که استفاده میکنید همگی فساد هستند. لیست کامل فسادهای لاراول رو میتونید اینجا ببینید. از اونجایی که من خودم با لاراول ۵ کار میکنم لینک هایی که به داکیومنت لاراول میدم هم به ورژن ۵ هست و شما میتونید اون بالا سمت راست، روی ورژن دلخواهتون سوئیچ کنید که البته توی این مورد تفاوت خاصی ندارن. شما میتونید توی لاراول فساد دلخواهتون رو تعریف و استفاده کنید و بعضی جاها کارتون رو خیلی جلو میندازه و البته نشان از حرفه ای بودن شما هم هست این کار. قبل از اینکه بپردازید به ساخت فساد برید و در مورد کانتینر لاراول اطلاعات کامل رو بدست بیارید.

    ساخت یک فساد – facade دلخواه در لاراول

    هر فسادی که شما میسازید توی لاراول، باید از کلاس پایه ی Facade مشتق شده باشن و حتما باید متد getFacadeAccessor  رو ایمپلیمنت کنید. توی این متد شما به لاراول میگید که وقتی این فساد رو صدا زدم، کدوم کلاس که توی کانتینر هست رو لود کنه. کلاس پایه ی Facade  از متد جادویی __callStatic()  برای این کار استفاده میکنه. بعد از ساخت یک فساد به راحتی میتونید به روش زیر به فساد متد مورد نظرتون دسترسی پیدا کنید :

    $value = Cache::get('key');

    برای ساخت یک فساد سه تا کار رو باید انجام بدید:

    اولین کاری که باید بکنید اینه که کلاس مورد نظرتون رو توی سرویس کانتینر بایند کنید. همونطور که گفتم قبلا در مورد این موضوع مطلبی نوشتم و میتونید توی خود داکیومنت لاراول هم در بارش بخونید. فرض کنید که یه کلاس مثل کلاس زیر رو داریم و میخوایم بصورت استاتیک و فسادگونه! ازش استفاده کنیم:

    namespace PaymentGateway;
    
    class Payment {
    
        public function process()
        {
            //
        }
    
    }

    قدم اول این بود که این کلاس رو در کانتینر بایند کنیم، بصورت زیر :

    App::bind('payment', function()
    {
        return new \PaymentGateway\Payment;
    });

    بهترین جا هم برای این کار همونطور که میدونید متد register  یک service provider هست که من اسمش رو میذارم PaymentServiceProvider.

    قدم دوم : حالا میتونید کلاس فسادتون رو بسازید.

    use Illuminate\Support\Facades\Facade;
    
    class Payment extends Facade {
    
        protected static function getFacadeAccessor() { return 'payment'; }
    
    }

    قدم سوم اینه که فساد رو به لاراول معرفی کنید. برای این کار باید توی config/app.php  یک نام اختصاری برای فساد خودتون بذارید :

    'Payment'       => 'Illuminate\Support\Facades\Payment',

    حالا به راحتی میتونید به روش آشنای زیر به متد های کلاستون دسترسی داشته باشید:

    Payment::process();

    مزایای استفاده از Facade بجای کلاس معمولی

    استفاده از فساد ها چند تا دلیل داره. اولی اینه که ظاهر ساده ای به شما میدن. ینی شما دیگه لازم نیست namespace های پیچیده رو بخاطر بسپارید. این مهمه ولی تنها دلیل استفاده از فساد نیست. دلیل بعدی که به نظرم مهمتر هم هست Testable بودن کد هایی هست که با فساد نوشته شدن. ینی چی حالا؟ ینی اینکه شما فساد ها رو خیلی راحت میتونید mock کنید و بگید که اگر این فساد رو صدا زدم این خروجی برگرده. چیزی که در کلاس معمولی بدون استفاده از interface قابل پیاده سازی نیست. مثال میزنم که دقیقتر بررسی کنیم. در مثالی که زدم از قابلیت automatic facade در لاراول استفاده کردم که در یه پست دیگه در موردش صحبت کردم. یه فولدر در دایرکتوری app\Base درست کردم که فایلهای زیر رو داخلش قرار دادم. ابتدا فایل Product.php بصورت زیر تعریف شده که همونطور که میبینید فضای نام Publisher پیشوند Facades داره که اون رو بصورت اتوماتیک فساد تبدیل کرده و ما میتونیم بصورت استاتیک به اون دسترسی داشته باشیم.

    <?php
    
    namespace App\Base;
    
    use Facades\App\Base\Publisher;
    
    class Product {
        public $name;
        public function __construct($name)
        {
            $this->name = $name;
        }
        public function publish() {
            Publisher::publish($this);
        }
    }

    و publisher.php که یک کلاس معمولی در PHP هست:

    <?php
    
    namespace App\Base;
    
    class Publisher
    {
        public function publish($product)
        {
            echo "Publishing the {$product->name}...";
            return true;
        }
    }

    میدونیم که consumer خیلی راحت میتونه با ویژگی automatic facade از این کلاس Publisher مثل یک فساد استفاده کنه:

    <?php
    
    use App\Base\Product;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/', function () {
        $product = new Product("Book");
        $product->publish();
    });

    من کد بالا رو در فایل web.php نوشتم. برای اینکه کد رو تست کنیم ابتدا کامند زیر رو بزنید که تست بسازه واستون:

    php artisan make:test ProductTest --unit 

    و تست رو اینجوری کامل کنید:

    <?php
    
    namespace Tests\Unit;
    
    use App\Base\Product;
    use Tests\TestCase;
    use Facades\App\Base\Publisher;
    
    class ProductTest extends TestCase
    {
        /** @test */
        public function it_can_publish_a_post() {
            $product = new Product("Book");
            Publisher::shouldReceive('publish')
                ->with($product)
                ->andReturn(true);
    
            $this->assertTrue($product->publish());
        }
    }

    همونطور که میبینید بدون اینکه نیاز باشه که کلاس پابلیشر ران بشه کد بالا چیزی که ما گفتیم بهش رو در اختیارمون قرار داده. در واقع DI یا همون Dependency Injection اومد که ما بتونیم نیازمندی ها رو از بیرون به کلاسها پاس بدیم که بتونیم بصورت testable کد بزنیم ولی میبینید که فساد ها در کنار داشتن فابلیت testablility به ما سادگی هم میدن و چیز خوبی هستن در مجموع. خروجی کد بالا چیزی مثل این خواهد بود:

     PASS  Tests\Unit\ProductTest
      ✓ it can publish a post
    
      Tests:  1 passed
      Time:   0.06s

    امیدوارم کمکی کرده باشه بهتون این پست. موفق باشید.

  • حذف کلید خارجی در لاراول

    همونطور که میدونید اگه یه کلید خارجی توی مایگریشن ها و متد up()  اضافه کنیم ، باید اون رو توی متد down()  حذفش کنیم و یا به اصطلاح drop کنیم. روابط رو میتونید در phpmyadmin->structure->Relation view  ببینید . برای حذف این روابط داکیومنت خود لاراول گفته این کار رو بکنید :

    To drop a foreign key, you may use the dropForeign method. Foreign key constraints use the same naming convention as indexes. So, we will concatenate the table name and the columns in the constraint then suffix the name with “_foreign”:

    $table->dropForeign('posts_user_id_foreign');

     

    یک راه دیگه که توی داکیومنت لاراول گفته نشده اینه :

    $table->dropForeign(['user_id']);

     

  • کار با بیش از یک دیتابیس در لاراول ۵

    بعضی وقتا نیازه که شما با بیش از یک دیتابیس در ارتباط باشید در لاراول ، مثلا ممکنه برای هر وبلاگی که توی سیستم وبلاگ دهی شما ایجاد میشه یک دیتابیس درست کنید(البته فک نکنم تو این مورد ، این کار معقول باشه) اونجا نیاز هست که در اولین قدم توی فایل config/database.php  کانکشن مربوط به این کار رو ایجاد کنید. بصورت پیشفرض ۴ کانکشن در لاراول ۵ تعریف شده که میتونید شما هم کانکشن دیگه ای برای استفاده تعریف کنید.

    تعریف کانکشن برای اتصال به بیش از یک دیتابیس

    'mysql2' => [
                'driver'    => 'mysql',
                'host'      => env('DB_EXT_HOST', 'localhost'),
                'database'  => env('DB_EXT_DATABASE', 'db2'),
                'username'  => env('DB_EXT_USERNAME', 'username'),
                'password'  => env('DB_EXT_PASSWORD', 'password'),
                'charset'   => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix'    => '',
                'strict'    => false,
            ],

    توی کد بالا ما کانکشن mysql2  رو تعریف کردیم. دقت داشته باشید که کد بالا باید درون connectios تعریف کنید. همچنین توی ریشه اصلی پروژه و توی فایل .env  هم کانکشن باید مشخص شه… اون فایل رو ادیت کنید و مقادیر دلخواهتون رو اضافه کنید :

    DB_EXT_HOST=localhost
    DB_EXT_DATABASE=db2
    DB_EXT_USERNAME=username
    DB_EXT_PASSWORD=password

    حالا کانکشن های شما آماده هستند و میتونید به روشی که در ادامه میگم از اونها استفاده کنید.

    تغییر کانکشن پیشفرض در لاراول

    برای اینکه در کل پروژه کانکشن پیشفرض رو تغییر بدیم ، در فایل config/database.php  مقدار ‘default’ => ‘mysql’,  رو به ‘default’ => ‘mysql2’,  تغییر میدیم. در این صورت در کل پروژه شما mysql2 بعنوان کانکشن دیفالت استفاده خواهد شد.

    استفاده از یک کانکشن در یک مدل خاص

    اما گاهی لازمه که در یک مدل از یک کانکشن خاص استفاده بشه ، برای انجام این کار به روش زیر عمل میکنیم :

    <?php
    class SomeModel extends Eloquent {
     
        protected $connection = 'mysql2';
     
    }

    از این پس تمام اتصالاتی که با مدل بالا به دیتابیس وصل میشه با کانکشن mysql2 خواهد بود.

    تغییر کانکشن در کنترلر

    شاید بخواید جزئی تر شید و بخواید درون یک کنترلر خاص کانکشن رو عوض کنید . برای اینکار به راحتی از روش زیر اشتفاده کنید :

    <?php
     
    class SomeController extends BaseController {
     
        public function someMethod()
        {
            $someModel = new SomeModel;
     
            $someModel->setConnection('mysql_2');
     
            $something = $someModel->find(1);
     
            return $something;
        }
     
    }

    همونطور که میبینید با استفاده از متد setConnection()  این کار شدنیه…

    و استفاده در Query Builder :

    برای استفاده از کانکشن دیگه توی کوئوری بیلدر هم بصورت زیر عمل میکنیم :

    	
    $users = DB::connection('mysql2')->select(...);

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

    امیدوارم به دردتون خورده باشم 🙂