2016-02-17 24 views
10

Trong Laravel, việc tạo cơ sở dữ liệu thường được thực hiện thông qua các nhà máy mô hình. Vì vậy, bạn xác định một kế hoạch chi tiết cho mẫu của bạn sử dụng dữ liệu Faker, và nói bao nhiêu trường hợp bạn cần:Laravel - Mối quan hệ hạt giống

$factory->define(App\User::class, function (Faker\Generator $faker) { 
    return [ 
     'name' => $faker->name, 
     'email' => $faker->email, 
     'password' => bcrypt(str_random(10)), 
     'remember_token' => str_random(10), 
    ]; 
}); 

$user = factory(App\User::class, 50)->create(); 

Tuy nhiên, cho phép nói mô hình tài khoản của bạn có một mối quan hệ hasMany với nhiều mô hình khác, giống như một mô hình Post ví dụ:

Post: 
    id 
    name 
    body 
    user_id 

Vì vậy, trong tình huống này, bạn muốn để gieo rắc bảng viết của bạn với thực tế người dùng đã được gieo mầm trong bảng người dùng của bạn. Đây dường như không được thảo luận một cách rõ ràng, nhưng tôi đã tìm ra sau đây trong các tài liệu Laravel:

$users = factory(App\User::class, 3) 
    ->create() 
    ->each(function($u) { 
     $u->posts()->save(factory(App\Post::class)->make()); 
    }); 

Vì vậy, trong nhà máy tài khoản của bạn, bạn tạo X số bài viết cho mỗi tài khoản bạn tạo ra. Tuy nhiên, trong một ứng dụng lớn, nơi có thể 50 - 75 Mô hình chia sẻ mối quan hệ với Mô hình người dùng, Seed Seeder của bạn về cơ bản sẽ tạo ra toàn bộ cơ sở dữ liệu với tất cả các mối quan hệ của nó.

Câu hỏi của tôi là: Đây có phải là cách tốt nhất để xử lý việc này không? Điều duy nhất tôi có thể nghĩ đến là Seed the Users trước (không gieo giống bất kỳ mối quan hệ nào), và sau đó kéo người dùng ngẫu nhiên từ DB khi cần thiết trong khi bạn đang gieo giống các Models khác. Tuy nhiên, trong trường hợp chúng cần phải là duy nhất, bạn phải theo dõi những Người dùng nào đã được sử dụng. Ngoài ra, có vẻ như điều này sẽ thêm rất nhiều truy vấn bổ sung cho quá trình tạo hạt giống.

Trả lời

4
$factory->define(App\User::class, function (Faker\Generator $faker) { 
    return [ 
     'name' => $faker->name, 
     'email' => $faker->email, 
     'password' => bcrypt(str_random(10)), 
     'remember_token' => str_random(10), 
    ]; 
}); 

$factory->define(App\Post::class, function (Faker\Generator $faker) { 
    return [ 
     'name' => $faker->name, 
     'body' => $faker->paragraph(1), 
     'user_id' => factory(App\User::class)->create()->id, 
    ]; 
}); 

Vì vậy, bây giờ nếu bạn làm điều này factory(App\Post::class, 4)->create() nó sẽ tạo 4 bài đăng khác nhau và trong quá trình này cũng tạo 4 người dùng khác nhau.

Nếu bạn muốn người dùng tương tự cho tất cả các bài viết những gì tôi thường làm là:

$user = factory(App\User::class)->create(); 
$posts = factory(App\Posts::class, 40)->create(['user_id' => $user->id]); 
+0

Cảm ơn bạn đã trả lời. Tôi đã thử những thứ như thế này. Tuy nhiên, nếu tôi muốn sử dụng cùng một nhóm Người dùng, giả sử, 20 mô hình khác, tôi cảm thấy rằng người gieo hạt của tôi bị lúng túng khá nhanh. Về cơ bản, tất cả logic hạt giống của tôi kết thúc xảy ra trong một tệp, bởi vì 'Người dùng' được liên kết với nhiều Mô hình khác. Nhưng có lẽ không có cách nào tốt hơn – djt

5

Cá nhân tôi nghĩ rằng một lớp seeder để quản lý các mối quan hệ là đẹp hơn sau đó lớp seeder tách ra, bởi vì bạn có tất cả các logic ở một nơi, vì vậy trong một cái nhìn, bạn có thể thấy những gì đang xảy ra. (Bất kỳ ai biết cách tiếp cận tốt hơn: hãy chia sẻ) :)

Một giải pháp có thể là: một DatabaseSeeder và phương thức riêng trong lớp để giữ cho phương thức 'chạy' sạch hơn một chút. Tôi có ví dụ dưới đây, trong đó có một User, Link, LinkUser (nhiều-nhiều) và một Note (nhiều-một).

Đối với quan hệ nhiều-nhiều, trước hết tôi tạo tất cả các liên kết và nhận các id được chèn. (vì các id là tự động-inc tôi nghĩ rằng các id có thể được lấy dễ dàng hơn (có được tối đa), nhưng không quan trọng trong ví dụ này). Sau đó, tạo người dùng và đính kèm một số liên kết ngẫu nhiên cho từng người dùng (nhiều người đến nhiều người). Nó cũng tạo ra các ghi chú ngẫu nhiên cho mỗi người dùng (ví dụ nhiều-một). Nó sử dụng phương pháp 'nhà máy'.

Nếu bạn thay thế 'Liên kết' cho 'Bài đăng', thao tác này sẽ hoạt động. (Bạn có thể loại bỏ phần 'Chú ý' sau đó ...)

(Ngoài ra còn có một phương pháp để đảm bảo bạn có 1 người dùng hợp lệ với thông tin đăng nhập của riêng bạn.)

<?php 

use Illuminate\Database\Seeder; 

class DatabaseSeeder extends Seeder 
{ 
    /** 
    * Run the database seeds. 
    * 
    * @return void 
    */ 
    public function run() 
    { 
     // Create random links 
     factory(App\Link::class, 100)->create(); 

     // Fetch the link ids 
     $link_ids = App\Link::all('id')->pluck('id')->toArray(); 

     // Create random users 
     factory(App\User::class, 50)->create()->each(function ($user) use ($link_ids) { 

      // Example: Many-to-many relations 
      $this->attachRandomLinksToUser($user->id, $link_ids); 

      // Example: Many-to-one relations 
      $this->createNotesForUserId($user->id); 
     }); 

     // Make sure you have a user to login with (your own email, name and password) 
     $this->updateCredentialsForTestLogin('[email protected]', 'John Doe', 'my-password'); 
    } 

    /** 
    * @param $user_id 
    * @param $link_ids 
    * @return void 
    */ 
    private function attachRandomLinksToUser($user_id, $link_ids) 
    { 
     $amount = random_int(0, count($link_ids)); // The amount of links for this user 
     echo "Attach " . $amount . " link(s) to user " . $user_id . "\n"; 

     if($amount > 0) { 
      $keys = (array)array_rand($link_ids, $amount); // Random links 

      foreach($keys as $key) { 
       DB::table('link_user')->insert([ 
        'link_id' => $link_ids[$key], 
        'user_id' => $user_id, 
       ]); 
      } 
     } 
    } 

    /** 
    * @param $user_id 
    * @return void 
    */ 
    private function createNotesForUserId($user_id) 
    { 
     $amount = random_int(10, 50); 
     factory(App\Note::class, $amount)->create([ 
      'user_id' => $user_id 
     ]); 
    } 

    /** 
    * @param $email 
    * @param $name 
    * @param $password 
    * @return void 
    */ 
    private function updateCredentialsForTestLogin($email, $name, $password) 
    { 
     $user = App\User::where('email', $email)->first(); 
     if(!$user) { 
      $user = App\User::find(1); 
     } 
     $user->name = $name; 
     $user->email = $email; 
     $user->password = bcrypt($password); // Or whatever you use for password encryption 
     $user->save(); 
    } 
} 
8

Bạn có thể sử dụng saveMany cũng.Ví dụ:

factory(User::class, 10)->create()->each(function ($user) { 
    $user->posts()->saveMany(factory(Posts::class, 5)->make()); 
}); 
+0

Tôi không biết về 'saveMany()' cho đến khi tôi thấy câu trả lời này. Cảm ơn bạn. :) – Vaughany

4

Bạn có thể làm điều này bằng việc đóng cửa trong ModelFactory như đã thảo luận here.

Giải pháp này hoạt động rõ ràng và thanh lịch với người nuôi.

$factory->define(App\User::class, function (Faker\Generator $faker) { 
    return [ 
     'name' => $faker->name, 
     'email' => $faker->email, 
     'password' => bcrypt(str_random(10)), 
     'remember_token' => str_random(10), 
    ]; 
}); 

$factory->define(App\Post::class, function (Faker\Generator $faker) { 
    return [ 
     'name' => $faker->name, 
     'body' => $faker->paragraph(1), 
     'user_id' => function() { 
      return factory(App\User::class)->create()->id; 
     }, 
    ]; 
}); 

Đối với seeder của bạn, sử dụng một cái gì đó đơn giản như thế này:

//create 10 users 
factory(User::class, 10)->create()->each(function ($user) { 
    //create 5 posts for each user 
    factory(Post::class, 5)->create(['user_id'=>$user->id]); 
}); 

Chú ý: Phương pháp này không tạo ra các mục không cần thiết trong cơ sở dữ liệu, thay vì các thuộc tính thông qua được giao TRƯỚC việc tạo ra các hồ sơ liên quan.

Các vấn đề liên quan