2016-01-08 1 views
10

J'ai trouvé this answer sur le sujet, mais cela ne fonctionne pas pour moi.Laravel changements created_at sur la mise à jour

Alors, je fais une entrée dans la base de données:

// Write lead to database 
$lead = Lead::create($lead_data); 

Et les horodatages ressemblent à cela, ce qui est bon:

| 2016-01-08 10:34:15 | 2016-01-08 10:34:15 | 

Mais je fais une demande à un serveur externe, et je dois mettre à jour la ligne:

$lead->user_id = $response['user_id']; 
$lead->broker_id = $response['broker_id']; 
$lead->save(); 

et le champ created_at obtient changé:

| 2016-01-08 04:34:17 | 2016-01-08 10:34:17 | 

Comment résoudre ce problème?

EDIT

je besoin d'une solution qui vient modifier le comportement sans suppression de colonnes ou remise à zéro des migrations. Le correctif doit être effectué sur une base de données en direct sans toucher aux données. Comme suggéré ci-dessous, j'ai essayé la migration suivante:

$table->datetime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'))->change(); 

mais rien ne se passe. Le champ created_at est toujours modifié lors de la mise à jour.

+0

Comment chargez-vous la variable $ lead avant de procéder à la mise à jour? –

+0

La variable '$ lead' est remplie avec la méthode' create', mais de toute façon, j'ai essayé cela aussi avec '$ lead = Lead :: find ($ lead-> id);' après l'écriture, le problème persiste. – Skatch

Répondre

21

Si vous utilisez Laravel 5.2 et que vous utilisez MySQL, il y a eu un "bug" introduit avec les horodatages. Vous pouvez lire tout sur le problème sur github here. Cela concerne les valeurs par défaut de l'horodatage, et MySQL attribue automatiquement les attributs DEFAULT CURRENT_TIMESTAMP ou ON UPDATE CURRENT_TIMESTAMP sous certaines conditions.

Fondamentalement, vous avez trois options.

  1. Mise à jour variables MySQL:

Si vous définissez la variable explicit_defaults_for_timestamp-TRUE, aucune colonne d'horodatage sera attribué CURRENT_TIMESTAMP DEFAULT ou ON UPDATE CURRENT_TIMESTAMP attribue automatiquement. Vous pouvez en savoir plus sur la variable here.

  1. Utilisez horodatages nullables:

Changer $table->timestamps()-$table->nullableTimestamps(). Par défaut, la commande $table->timestamps() crée des champs d'horodatage qui ne sont pas valables. En utilisant $table->nullableTimestamps(), vos champs d'horodatage seront nullables, et MySQL n'attribuera pas automatiquement le premier les attributs DEFAULT CURRENT_TIMESTAMP ou ON UPDATE CURRENT_TIMESTAMP.

  1. Définir les horodatages vous:

Au lieu d'utiliser $table->timestamps, utilisez-vous $table->timestamp('updated_at'); $table->timestamp('created_at');. Assurez-vous que votre champ 'updated_at' est le premier horodatage de la table, de sorte que ce soit celui qui attribue automatiquement les attributs DEFAULT CURRENT_TIMESTAMP ou ON UPDATE CURRENT_TIMESTAMP.

+0

J'ai besoin d'une solution que je peux implémenter sur une base de données en cours d'exécution. La réinitialisation des migrations et l'abandon des colonnes n'est pas une option. – Skatch

3

Skatch - Je pense que votre solution ci-dessus n'est pas tout à fait raison, mais est très bien dans ce cas.

Le problème est que vous obtenez la date PHP, pas l'horodatage MYSQL par défaut pour votre valeur par défaut. Lorsque vous exécutez cette migration, vous obtenez une instruction comme celle-ci:

alter table alter column created_at default '2016:02:01 12:00:00'; 

Notez la chaîne pour votre date. Lorsque vous exécutez votre migration, cette date sera toujours utilisée pour votre created_at, et non la date actuelle lorsqu'un enregistrement est ajouté plusieurs jours plus tard. Au lieu de faire "date ('Y: m: d H: i: s')", vous pouvez faire DB :: raw ('current_timestamp') pour résoudre ce problème.

(SRY, ne pouvait pas simplement ajouter un commentaire ci-dessus - ma réputation est pas assez élevé encore ...)

+0

Vous avez raison, je n'ai pas pensé à ça. Quoi qu'il en soit, j'ai tout essayé, y compris votre suggestion '$ table-> datetime ('created_at') -> default (DB :: raw ('CURRENT_TIMESTAMP')) -> change();', mais c'était la seule façon de fonctionner ... La prochaine fois je vais essayer de le faire avec SQL. – Skatch

+1

Avez-vous besoin de le faire via une migration? La commande SQL native est directe: "alter table mytable modifier la colonne mycolumn timestamp par défaut current_timestamp NOT NULL à la mise à jour current_timestamp;" Exécutez cela sur la base de données directement et tout devrait être corrigé. (test d'abord!). Si vous devez le faire via une migration, vous pouvez le faire avec DB :: unprepared ($ MyRawSQL) ;. Quelque chose comme public function up() {Schema :: create (....); DB :: non préparé ($ MySQL); } – sgrover

+0

- Cela contourne également le bug mentionné par @patricus. – sgrover

1

ce détachement comme une réponse de haut niveau, résumant notre discussion de commentaires. D'abord, il y a une date bug introduite dans Laravel - comme noté par @patricus. Les solutions suggérées dans la discussion de bogue sont d'utiliser nullableTimestamps() au lieu de simplement timestamps(), ou de créer les champs created_at et updated_at directement - $table->timestamp('updated_at')->change().

Cela peut également être corrigé avec SQL brut. Une déclaration similaire à ce ALTER

alter table loader_rawvalues MODIFY column updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 

qui peut être appliqué directement sur vos tables de DB existantes (Testez d'abord, ou bien sûr!). OU vous pouvez utiliser DB :: unprepared() pour l'appliquer depuis votre migration, par exemple:

class CreateMyTable extends Migration 
{ 
    public function up() 
    { 
     Schema::create('mytable', function (Blueprint $table) { 
      $table->bigIncrements('id'); 
      // ... 
      $table->timestamps(); 
     }); 

     DB::unprepared('alter table mytable MODIFY column updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'); 
    } 
} 
+0

Je pense que vous devez modifier le champ created_at sans une instruction 'ON UPDATE', updated_at fonctionne très bien.:) – Skatch

+0

Pour confirmer, si vous devez exécuter une migration pour corriger le problème updated_at, en fonction de la solution de sgrover, vous pouvez ajouter ce qui suit à votre migration pour toutes les tables qui doivent être réparées sans être supprimées: DB :: unprepared (' modifier faqs de table modifier current_timestamp par défaut d'horodatage created_at colonne NOT NULL '); ' avec ' DB :: sans préparation (' alter faqs de table modifier colonne updated_at current_timestamp par défaut timestamp NOT NULL '); ' Cela va régler le tIMESTAMP par défaut à la CURRENT TIMESTAMP et supprimer la règle ON UPDATE supplémentaire. –