Bonjour,

J'ai remarqué qu'en developpant avec Laravel+VueJS j'etais confronté à un probème: un double accès quasi systematique à la BDD.
Mettons que l'appli affiche des Posts de Users.
Dans le cas d'un accès de type GET /Post/123 je veux m'assurer que Post appartient à auth()->user().

Coté PHP je fais:

Public function show($id) {
    $post = Post::find(123);
    if($post->user->id == auth()->user()->id){
        if($request->isXmlHttpRequest()){
            return response()->json($post);
        else {    
            return view(posts.show, compact('post'));
        }
     } else {
        return back()->withErrors(...);
     }
}

Mais comme mon objet Post est très complexe, dans la view qui appelle un composant VUE-JS je ne peux pas le passer attribut par attribut, je fournis donc la route pour le recuperer en AJAX:

<mon-composant
        route-to-post="{{ route('post.show', ['id' => $post->id]) }}">
</mon-composant>        

Ce que j'aimerai

La solution précédante fais qu'il faut 2 accès à la BDD: 1 fois en PHP puis 1 autre fois en AJAX pour traiter mon pb.
Quelqu'un aurait une astuce pour eviter cette redondance d'accès?

9 réponses


PhiSyX
Réponse acceptée

Mais pourquoi tu ne passes pas ton object $post directement à ta vue?
<mon-composant :post="{{ $post (jsonifier) }}"></mon-composant>

La solution serait de ne pas charger les posts en php mais en ajax avec vue.

Merci @arnich.
Oui mais si coté PHP je charge le Post c'est pour pouvoir faire le test d'appartenance et faire un return back() avant de construire et afficher la page qui contient le composant. Si je ne le fait pas je prend le risque d'autoriser l'affichage de ce composant et de n'y mettre aucune donnée. Y'a bien une solution qui me vient là: remplacer le return back() coté PHP par un window.location.href coté client client mais je bloque sur un point: comment obtenir l'url complete d'un return back()->withInputs()->withErrors(...) et la passer en variable à mon composant?

<mon-composant
        route-to-post="{{ route('post.show', ['id' => $post->id]) }}"
        route-to-return-back="{{  ????  }}">
</mon-composant>

Ton deuxième appel se trouve ici

auth()->user()->id

en passant par auth()->user()->id() tu fetch l'object complet. En utilisant aut()->id() , tu peut récupérer la primary key depuis le cache.
pas de double appelle du coup.

@Goopil: Interressante cette remarque, je ne savais pas ça.

Sinon ce n'est pas tant cela qui me gêne, c'est le fait que dans la vue (nommée ici < mon-composant>) je refait un appel en AJAX afin de recuperer l'objet complet "POST" directement en javascript. Si je ne le fais pas, je suis obligé de faire un truc du genre

<mon-composant
    post-name="{{ $post->name }}"
    post-title = "{{ $post->title }}"
    post-description = "{{ $post->description }}"
    ....
    post-attr-number-a-ne-plus-en-finir="{{ $post->attr2000" }}
></mon-composant>

Merci @PhiSyx, trop cool, ça fonctionne (mais sans les : car c'est un composant de l'html et non imbriqué dans un autre)!

<mon-composant
        post="{{ json_encode($post) }}"
></mon-composant>

Et dans la Vue javascript y'a plus qu'à faire

JSON.parse(this.post)

C'est impec. Il me restait une question. Y'a-t-il une limite de taille à l'attribut XML? car le html généré ressemble à ça:

<mon-composant
    post="{&quot;id&quot;:4,&quot;created_at&quot;:&quot;2016-12-12 10:35:23&quot;,&quot;updated_at..... long long long!! }"
></mon-composant>

En cherchant un peu à priori pas de limite de taille, mon objet $post peut etre de n'importe quelle taille.
Merci encore!

Non pas de limite, mais peu importe car Vue va enlever toutes propriétés/attributs de l'HTML si tu les as déclarés avec la propriété props de Vue. (props: ['post']) Ce qui semble etre le cas.
Mais si cela te dérange, ce que j'peux comprendre, tu peux mettres tes données $post (json) au niveau de ton instance Vue dans la fonction data de Vue.

ex: (à adapter)

<?php
$post = [
  'title' => 'Coucou je suis un poney :-)',
  'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti quod saepe tempora explicabo fugit, suscipit delectus, optio, ratione eveniet ab facere laudantium at quibusdam magnam. Molestiae quia laborum at recusandae!',
];
?>

Vue.component('mon-composant', {
  props: ['post'],
  template: '<pre>Mon objet {{ post }} ---> {{ post.title }}</pre>'
})

var post = new Vue({
  el: '#post',
  data: function () {
    return {
      post: <?= json_encode($post) ?>
    }
  },
  template: '<mon-composant :post="post"></mon-composant>'
})

Le : est important, c'est ce qui va permette à Vue de comprendre qu'il s'agit d'un Object et non d'une String. (Ce qui t'éviterai entre autre de JSON.parse(this.post) ^^)

Ha oui ok, , merci PhiSyx. Je comprend mieux maintenant. Effectivement je ne savait pas (non plus encore une fois :-) ) que l'on pouvait déclarer props: ['post'] dans la déclaration du component. (ce que je fais pourtant avec tous mes components sous-jacents!)
Je débute en Vue-JS et tes conseilles me sont bien précieux du coup.
Je vais pouvoir épurer mon appli, ça va être beaucoup plus sain maintenant comme ça.
Merci encore.

En fait comme VUE-JS ne compile la vue que coté client, il est tout de même obligatoire à un moment donné d'envoyer les données sous forme XML:

Qu'on utilise les : ou pas on retrouvera quand même ça dans la source html si le composant est racine

<mon-composant
    post="{&quot;id&quot;:4,&quot;created_at&quot;:&quot;2016-12-12 10:35:23&quot;,&quot;updated_at..... long long long!! }"
></mon-composant>