在Laravel 5中使用UUID作为主键

时间:2015-08-04 18:55:05

标签: php mysql laravel laravel-5 eloquent

我尝试创建的表格的主键是一个UUID,定义为binary(16),而不是默认的自动递增id字段。

我设法使用原始SQL语句创建迁移,DB::statement如下:

DB::statement("CREATE TABLE `binary_primary_keys` (
                      `uuid` binary(16) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
                      `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
                      `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
                      PRIMARY KEY (`uuid`)
                  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;");

但是,我无法让模型正常工作。我已经按照可用的教程here进行了操作。我已经定义了我的模型:

class UuidModel extends Model
{
    public $incrementing = false;
    public $primaryKey = 'uuid';

    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        /**
         * Attach to the 'creating' Model Event to provide a UUID
         * for the `id` field (provided by $model->getKeyName())
         */
        static::creating(function ($model) {
            $model->{$model->getKeyName()} = (string)$model->generateNewId();
            echo($model->{$model->getKeyName()});
        });
    }

    /**
     * Get a new version 4 (random) UUID.
     */
    public function generateNewId()
    {
        return Uuid::generate();
    }
}

其中UuidWebpatser\Uuid的别名。

我遇到的一个问题是我无法从UuidModel派生Eloquent,如教程中所述。事实上,我没有看到Eloquent课程。我来自Model。我猜这个教程是用Laravel 4编写的。

我很感激帮助实现将UUID作为Laravel 5中的主键的表。

编辑1: 所以,如果我这样定义我的类:

use Illuminate\Database\Eloquent
class UuidModel extends Eloquent { ... }

我收到以下错误:

PHP Fatal error:  Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8

如果我删除use Illuminate\Database\Eloquent行,则会收到以下错误:

PHP Fatal error:  Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8

编辑2: 我发现在创建static::creating的实例时,永远不会调用UuidModel事件。

我尝试在creating中设置AppServiceProvider事件监听器,但也没有被调用。有趣的是,creating事件不是为常规Laravel生成的模型User调用的。

class AppServiceProvider extends ServiceProvider
{
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    /**
     * Attach to the 'creating' Model Event to provide a UUID
     * for the `id` field (provided by $model->getKeyName())
     */
    echo "Booting...\n";
    UuidModel::creating(function ($model) {
        echo "Creating Uuid Model...\n";
        $model->{$model->getKeyName()} = (string)$model->generateNewId();
    });

    User::creating(function($user){
        echo "Creating User Model...";
        $user->name = 'Forced Name in boot()';
    });
}
public function register(){}

}

4 个答案:

答案 0 :(得分:2)

所以,我觉得这个东西就像一个魅力(没有经过测试的单元测试):

  1. class UuidModel extends Eloquent是一个较旧的(Laravel 4)构造。我们在Laravel 5中使用class UuidModel extends Model
  2. 解决方案是移动

    UuidModel::creating(function ($model) {
        echo "Creating Uuid Model...\n";
        $model->{$model->getKeyName()} = (string)$model->generateNewId();
    });
    

    AppServiceProvider::boot()EventServiceProvider::boot()。无需其他更改。一切都按预期工作。

  3. 我仍然不知道为什么(2)在EventServiceProvider中工作而在AppServiceProvider中工作,正如官方docs中所解释的那样。但从名称来看,这可能是它的意图。

答案 1 :(得分:2)

将36chr UUID存储为二进制(16)的想法如何:

IMO在没有Laravel生成UUID 的情况下有 优势。也就是说,如果新记录(将来的某一天)从应用程序外部插入到数据库中,则会正确填充UUID字段。

我的建议:使用迁移创建UUID默认值触发器

(此触发器使DataBase服务器完成每次插入新客户时生成UUID的工作)

<?php namespace MegaBank\HighInterestLoans\Updates;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;

class MigrationTriggerForCustomers extends Migration
{
public function up()
    {

        DB::unprepared('CREATE TRIGGER before_insert_customers
                      BEFORE INSERT ON    
                    `megabank_highinterestloans_customers` 
                      FOR EACH ROW
                      SET new.uuid = UNHEX(REPLACE(UUID(), "-","");');
    }

    public function down()
    {
        DB::unprepared('DROP TRIGGER `before_insert_customers`');
    }
}

最后,如果您想获得UUID的人类可读版本,请执行以下操作:

SELECT HEX(UUID) FROM customers;

无论如何,希望这有助于某人: - )

答案 2 :(得分:0)

这是一种不使用事件的快速解决方案。

UUidModel.php

<?php        namespace App;

    use \Illuminate\Database\Eloquent\Model;

    use \Illuminate\Database\Eloquent\Builder;

    class UuidModel extends Model

    {

    /**

    * Insert the given attributes and set the ID on the model.

    *

    * @param  \Illuminate\Database\Eloquent\Builder  $query

    * @param  array  $attributes

    * @return void

    */

        protected function insertAndSetId(Builder $query, $attributes)

        {
            $keyName = $this->getKeyName();
            $id = $attributes[$keyName] = $this->generateNewId();
            $query->insert($attributes);
            $this->setAttribute($keyName, $id);
        }

    /**
    * Get a new version 4 (random) UUID.
    */
        public function generateNewId()
        {
            return 'uuid!!' ;// just for test
        }
    }
?>

模型示例Car.php

<?php namespace App;

    class Car extends UuidModel {
    }

答案 3 :(得分:-1)

也尝试使用此包将自动生成并在您的模型中指定UUID字段,也可以通过UUID键显示和更新。

https://github.com/EmadAdly/laravel-uuid