In Développement Dernière mise à jourated:
Partager sur:
Logiciel Jira est l'outil de gestion de projet n°1 utilisé par les équipes agiles pour planifier, suivre, publier et prendre en charge d'excellents logiciels.

Les modèles et leurs relations sont au cœur de Laravel Eloquent. S'ils vous donnent du fil à retordre ou si vous ne parvenez pas à trouver un guide simple, convivial et complet, commencez ici!

Assis de l'autre côté de leur article de programmation, il est facile pour le writer feindre ou faire exploser l'aura de l'expertise/du prestige du platle formulaire fournit. Mais je vais être honnête : j'ai eu un extrêmement temps dur apprendre Laravel, ne serait-ce que parce que c'était mon premier framework full-stack. L’une des raisons était que je ne l’utilisais pas au travail et que je l’explorais par curiosité ; donc, je ferais une tentative, j'arriverais à un point, je serais confus, j'abandonnerais et éventuellementally oublie tout. J'ai dû le faire 5 à 6 fois avant que cela commence à avoir un sens pour moi (bien sûr, la documentation n'aide pas).

Mais ce qui n'avait toujours pas de sens était Eloquent. Ou du moins, les relations entre les modèles (car Eloquent est trop grand pour apprendre complètement). Les exemples de modélisation des auteurs et des articles de blog sont une blague car les vrais projets sont beaucoup plus complexes; malheureusement, les documents officiels utilisent les mêmes exemples (ou similaires). Ou même si je suis tombé sur un article / une ressource utile, l'explication était si mauvaise ou si manquante qu'elle était tout simplement inutile.

(Au fait, j'ai déjà été attaqué pour avoir attaqué la documentation officielle, donc si vous avez des idées similaires, voici ma réponse standard: allez consulter la documentation de Django puis parlez-moi.)

Événementally, bit by bit, cela s’est mis en place et avait du sens. J'étais bienally capable de modéliser correctement des projets et d’utiliser les modèles confortablement. Puis un jour, je suis tombé sur quelques astuces intéressantes dans les collections qui rendent ce travail plus agréable. Dans cet article, j'ai l'intention de couvrir tout cela, en commençant par les bases, puis en couvrant tous les cas d'utilisation possibles que vous rencontrerez dans des projets réels.

Pourquoi les relations avec les modèles éloquents sont-elles difficiles?

Malheureusement, je rencontre beaucoup trop de développeurs Laravel qui ne comprennent pas correctement les modèles.

Mais pourquoi?

Même aujourd'hui, alors qu'il y a une explosion de cours, d'articles et de vidéos sur Laravel, la compréhension globaleanding est pauvre. Je pense que c'est un point important et mérite réflexion.

Si vous me le demandez, je dirai que les relations modèles éloquentes ne sont pas difficiles du tout. Du moins du point de vue de la définition de « dur ». Les migrations de schémas en direct sont difficiles ; écrire un nouveau sujetplatle moteur est dur ; contribuer au code au cœur de Laravel est difficile. Par rapport à ceux-ci, apprendre et utiliser un ORM . . . eh bien, ça ne doit pas être difficile ! 🤭🤭

Quel acteally ça arrive, c'est que Développeurs PHP apprenant Laravel trouver Eloquent dur. C'est le vrai problème sous-jacent, et à mon avis, plusieurs facteurs y contribuent (alerte d'opinion sévère et impopulaire!):

  • Avant Laravel, l'exposition à un framework pour la plupart des développeurs PHP était CodeIgniter (c'est toujours alive, d'ailleurs, même si c'est devenu plus Laravel/Cakede type PHP). Dans l'ancienne communauté CodeIgniter (s'il y en avait une), la « meilleure pratique » consistait à coller directement les requêtes SQL là où c'était nécessaire. Et bien que nous ayons un nouveau CodeIgniter aujourd'hui, le habits ont reporté. En conséquence, lorsque apprendre Laravel, l'idée d'un ORM est 100% nouvelle pour les développeurs PHP.
  • En ignorant le très faible pourcentage de PHP exposé à des frameworks tels que Yii, CakePHP, etc., les autres sont habitués à travailler en PHP de base ou dans un environnement tel que WordPress. Et là encore, un état d'esprit basé sur la POO n'existe pas, donc un framework, un conteneur de services, un design pattern, un ORM. . . ce sont des concepts extraterrestres.
  • Il existe peu ou pas de concept d’apprentissage continu dans le monde PHP. Le développeur moyen est heureux de travailler avec des configurations à serveur unique utilisant des bases de données relationnelles et émettant des requêtes écrites sous forme de chaînes. UNsyncprogrammation horaire, sockets Web, HTTP 2/3, Linux (oubliez Docker), tests unitaires, Domain-Driven Design - ce sont autant d'idées étrangères à une écrasante proportion de développeurs PHP. En conséquence, lire quelque chose de nouveau et de stimulant, au point que l'on trouve cela confortable, n'arrive pas lorsque l'on rencontre Eloquent.
  • La compréhension globaleandiLa gestion des bases de données et de la modélisation est également médiocre. Étant donné que la conception de bases de données est directement et indissociablement liée aux modèles Eloquent, elle place la barre de difficulté plus haut.

Je ne veux pas être dur et généraliser le mondeally - il y a excellent Les développeurs PHP aussi, et beaucoup d'entre eux, mais leur pourcentage global est très faible.

Si vous lisez ceci, cela signifie que vous avez franchi toutes ces barrières, rencontré Laravel et joué avec Eloquent.

Toutes nos félicitations! 👏

Tu y es presque. Tous les éléments de base sont en place et il suffit de les parcourir dans le bon ordre et dans les détails. En d'autres termes, commençons au niveau de la base de données.

Modèles de base de données: relations et cardinalité

Pour simplifier les choses, supposons que nous travaillons avec bases de données relationnelles seulement tout au long de cet article. L'une des raisons est que les ORM étaient originairesally développé pour les bases de données relationnelles ; l'autre raison est que les SGBDR sont toujours extrêmement populaires.

Modèle de données

Tout d'abord, comprenons mieux les modèles de données. L'idée d'un modèle (ou d'un données modèle, pour être plus précis), provient de la base de données. Pas de base de données, pas de données et donc pas de modèle de données. Et qu'est-ce qu'un modèle de données? C'est tout simplement la façon dont vous décidez de stocker / structurer vos données. Par exemple, dans un magasin de commerce électronique, vous pouvez tout stocker dans une seule table géante (pratique HORRIBLE, mais malheureusement, pas rare dans le monde PHP); ce serait votre modèle de données. Vous pouvez également diviser les données en 20 tables principales et 16 tables de connexion; c'est aussi un modèle de données.

Notez également que la façon dont les données sont structurées dans la base de données ne doit pas nécessairement correspondre à 100 % à la façon dont elles sont organisées dans l'ORM du framework. Cependant, le effort est toujours de garder les choses aussi proches que possible afin que nous n'ayons plus une chose à prendre en compte lors du développement.

Cardinalité

Éliminons également rapidement ce terme : cardinalité. Il fait simplement référence au « compte », vaguement speaking. Donc 1, 2, 3. . . tout cela peut être la cardinalité de quelque chose. Fin de l'histoire. Continuons d'avancer !

Les relations

Désormais, chaque fois que nous stockons des données dans n'importe quel type de système, il existe des moyens pour les points de données d'être stockés. related les uns aux autres. Je sais que ça sonne abstract et ennuyeux, mais supportez-moi un peu. Les façons dont les différents éléments de données sont connectés sont appelées des relations. Voyons d'abord quelques exemples non liés à la base de données afin d'être convaincus que nous comprenons parfaitement l'idée.

  • Si nous stockons tout dans un tableau, un possible relation amoureuse est : l'élément de données suivant se trouve à un index greater que le previndice ious par 1.
  • Si nous stockons des données dans un arbre binaire, une relation possible est que l'arbre enfant à gauche a toujours des valeurs plus petites que celles du nœud parent (si nous choisissons de maintenir l'arbre de cette façon).
  • Si nous stockons des données sous la forme d'un tableau de tableaux de longueur égale, nous pouvons imiter une matrice, puis ses propriétés deviennent les relations pour nos données.

On voit donc que le mot «relation», dans le contexte des données, n'a pas de sens fixe. En fait, si deux personnes regardaient les mêmes données, elles pourraient identifier deux relations de données très différentes (bonjour, statistiques!) Et les deux pourraient être valides.

Relationnel bases de données

Sur la base de tous les termes dont nous avons discuté jusqu'à présent, nous pouvons trouverally parlez de quelque chose qui a un lien direct avec des modèles dans un framework Web (Laravel) – des bases de données relationnelles. Pour la plupart d'entre nous, la base de données principale utilisée est MySQL, MariaDB, PostgreSQL, MSSQL, SQL Server, SQLite ou quelque chose du genre. Nous savons peut-être aussi vaguement qu'ils s'appellent SGBDR, mais la plupart d'entre nous ont oublié de quoi il s'agit.ally signifie et pourquoi est-ce important.

Le « R » dans SGBDR signifie Relationnel, bien sûr. Ce n'est pas un ARbitterme rarement choisi; nous soulignons ainsi le fait que ces systèmes de bases de données sont conçus pour fonctionner efficacement avec les relations entre les données stockées. En fait, « relation » a ici un sens strict.thematictout le sens, et même si aucun développeur n'a besoin de s'en soucier, il est utile de savoir qu'il existe un rigorous mamanthematical fondation sous ces types de bases de données.

Explorez ces ressources pour apprendre SQL et NoSQL.

D'accord, nous savons donc par expérience que les données du SGBDR sont stockées sous forme de tables. Où sont donc les relations?

Types de relations dans le SGBDR

C'est peut-être la partie la plus importante de tout le sujet de Laravel et des relations modèles. Si vous ne comprenez pas cela, Eloquent n'aura jamais de sens, alors faites attention pendant les prochaines minutes (ce n'est même pas si difficile).

Un SGBDR permet nous devons avoir des relations entre les données – au niveau de la base de données. Cela signifie que ces relations ne sont pas impraticables/imaginaires/subjectives et peuvent être créées.ated ou déduit par différentes personnes avec le même résultat.

En même temps, il existe certaines capacités/outils au sein d'un SGBDR qui nous permettent de créerate et appliquer ces relations, telles que :

  • Clé primaire
  • Clé étrangère
  • contraintes

Je ne veux pas que cet article devienne un cours sur les bases de données, je suppose donc que vous connaissez ces concepts. Sinon, ou au cas où vous vous sentirez fragile dans votre confiance, je vous recommande cette vidéo conviviale (n'hésitez pas à explorer toute la série):

Il se trouve que ces relations de type SGBDR sont également les plus courantes qui se produisent dans les applications du monde réel (pas toujours, car un réseau social est mieux modélisé sous forme de graphique et non comme une collection de tableaux). Alors, regardons-les un par un et essayons également de comprendre où ils pourraient être utiles.

Relation individuelle

Dans presque toutes les applications Web, il existe des comptes d'utilisateurs. De plus, les éléments suivants sont vrais (genreally speaking) sur les utilisateurs et les comptes :

  • Un utilisateur ne peut avoir qu'un seul compte.
  • Un compte ne peut appartenir qu'à un seul utilisateur.

Oui, on peut affirmer qu'une personne peut s'inscrire avec un autre email et ainsi créerate deux comptes, mais du point de vue de l'application Web, ce sont deux personnes différentes avec deux comptes différents. L'application n'affichera pas, par exemple, les données d'un compte dans un autre.

Tout cela signifie que si vous rencontrez une situation comme celle-ci dans votre application et que vous utilisez une base de données relationnelle, vous devrez la concevoir comme une relation un-à-un. Notez que personne ne vous force artificiellementally — il y a une situation claire dans le domaine des affaires et le vous utilisez une base de données relationnelle. . . ce n'est que lorsque ces deux conditions sont remplies que vous parvenez à une relation individuelle.

Pour cet exemple (utilisateurs et comptes), voici comment nous pouvons implémenter cette relation lors de la création du schéma:

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    email VARCHAR(100) NOT NULL,
    password VARCHAR(100) NOT NULL,
    PRIMARY KEY(id)
);

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    role VARCHAR(50) NOT NULL,
    PRIMARY KEY(id),
    FOREIGN KEY(id) REFERENCES users(id)
);

Vous remarquez l'astuce ici ? C'est assez rare lors de la création d'applicationsally, mais dans le accounts table, nous avons le terrain id défini à la fois comme clé primaire et clé étrangère! La propriété de clé étrangère la relie au users table (bien sûr 🙄) alors que la propriété de clé primaire rend le id colonne unique - une vraie relation un-à-un!

Certes, la fidélité de cette relation n'est pas garantie. Par exemple, rien ne m'empêche d'ajouter 200 nouveaux utilisateurs sans ajouter une seule entrée au accounts table. Si je fais ça, je me retrouve avec un one-to-zero relation! 🤭🤭 Mais dans les limites de la structure pure, c'est le mieux que nous puissions faire. Si nous voulons prevPour ajouter des utilisateurs sans compte, nous devons nous aider d'une sorte de logique de programmation, soit sous la forme de déclencheurs de base de données, soit de validations appliquées par Laravel.

Si vous commencez à vous stresser, j'ai de très bons conseils:

  • Vas-y doucement. Aussi lentement que nécessaire. Au lieu d’essayer de terminer cet article et les 15 autres que vous avez mis en favoris pour aujourd’hui, tenez-vous-en à celui-ci. Laissez cela prendre 3, 4, 5 jours si c'est ce qu'il faut - votre objectif devrait être de knock Des relations modèles éloquentes hors de votre liste pourreveuh. Vous avez déjà sauté d'article en article, perdant plusieurs centaines d'heures et pourtant cela n'a pas aidé. Alors, faites quelque chose de différent cette fois. 😇
  • Bien que cet article concerne Laravel Eloquent, tout cela vient en grande partie later. La base de tout cela est le schéma de base de données, nous devrions donc nous concentrer d'abord sur la bonne solution. Si vous ne pouvez pas travailler uniquement au niveau d’une base de données (en supposant qu’il n’existe pas de framework dans le monde), alors les modèles et les relations n’auront jamais de sens. Alors, oubliez Laravel pour le moment. Complètement. Nous parlons et faisons uniquement de la conception de bases de données pour le moment. Oui, je ferai des références à Laravel de temps en temps, mais votre travail consiste à les ignorer complètement si elles compliquent la situation pour vous.
  • Later Continuez, lisez-en un peu plus sur les bases de données et ce qu’elles proposent. Index, performances, déclencheurs, structures de données sous-jacentes et leur comportement, mise en cache, relations dans MongoDB. . . quoiateTous les sujets tangentiels que vous pouvez aborder vous aideront en tant qu'ingénieur. N'oubliez pas que les modèles-cadres ne sont que des fantômes shells; la véritable fonctionnalité d'un platLe formulaire provient de ses bases de données sous-jacentes.

Relation un-à-plusieurs

Je ne sais pas si vous l'avez réalisé, mais c'est le type de relation que nous créons tous intuitivement.ate dans notre travail quotidien. Quand nous créonsate an orders table (un exemple hypothétique), par exemple, pour stocker une clé étrangère dans le users table, nous créonsate une relation un-à-plusieurs entre les utilisateurs et les commandes. Pourquoi donc? Eh bien, regardez-le à nouveau du point de vue de qui peut en avoir combien : un utilisateur est autorisé à avoir plus d'une commande, ce qui est à peu près ainsi que fonctionne tout commerce électronique. Et vu du côté opposé, la relation dit qu’une commande ne peut appartenir qu’à un seul utilisateur, ce qui est également très logique.

Dans la modélisation des données, les livres SGBDR et la documentation du système, cette situation est représentée schématiquementally comme ça:

Remarquez les trois lignes faisant une sorte de trident? C'est le symbole pour «plusieurs», et donc ce diagramme indique qu'un utilisateur peut avoir plusieurs commandes.

Soit dit en passant, ces « plusieurs » et « un » comptent que nous rencontrons à répétition.atesont ce qu'on appelle la cardinalité d'une relation (rappelez-vous ce mot d'aprevsection intéressante ?). Encore une fois, pour cet article, le terme n'a aucune utilité, mais il aide à connaître le concept au cas où il reviendrait lors d'entretiens ou de lectures complémentaires.

Simple, non? Et en termes de SQL réel, la création de cette relation est également simple. En fait, c'est beaucoup plus simple que le cas d'une relation en tête-à-tête!

CREATE TABLE users( 
    id INT NOT NULL AUTO_INCREMENT, 
    email VARCHAR(100) NOT NULL, 
    password VARCHAR(100) NOT NULL, 
    PRIMARY KEY(id) 
);

CREATE TABLE orders( 
    id INT NOT NULL AUTO_INCREMENT, 
    user_id INT NOT NULL, 
    description VARCHAR(50) NOT NULL, 
    PRIMARY KEY(id), 
    FOREIGN KEY(user_id) REFERENCES users(id) 
);

La orders table stocke les ID utilisateur pour chaque commande. Puisqu'il n'y a aucune contrainte (restriction) que les ID utilisateur dans le orders La table doit être unique, cela signifie que nous pouvons répéter un seul identifiant plusieurs fois. C'est ce que créeateC'est la relation un-à-plusieurs, et non une magie obscure cachée en dessous. Les identifiants utilisateur sont stockés de manière stupide dans le orders table, et SQL n'a aucun concept de un-à-plusieurs, un-à-un, etc. Mais une fois que nous stockons les données de cette façon, nous pouvons penser de l'existence d'une relation un-à-plusieurs.

Espérons que cela a du sens maintenant. Ou du moins, plus de sens qu'avant. 😅 N'oubliez pas que, comme toute autre chose, c'est une simple question de pratique, et une fois que vous avez fait cela 4 à 5 fois dans des situations réelles, vous n'y penserez même pas.

Relations plusieurs-à-plusieurs

Le prochain type de relation qu'unriseEn pratique, c'est ce qu'on appelle la relation plusieurs-à-plusieurs. Encore une fois, avant de nous soucier des frameworks ou même de plonger dans les bases de données, pensons à un analogue du monde réel : les livres et les auteurs. Pensez à votre auteur préféré ; ils ont écrit plus d'un livre, n'est-ce pas ? En même temps, il est assez courant de voir plusieurs auteurs collaborer sur un livre (du moins dans le genre non-fiction). Ainsi, un auteur peut écrire plusieurs livres, et plusieurs auteurs peuvent écrire un seul livre. Entre les deux entités (livre et auteur), cela forme une relation plusieurs-à-plusieurs.

Maintenant, étant donné qu'il est très peu probable que vous créiezate une application du monde réel impliquant des bibliothèques ou des livres et des auteurs, pensons donc à quelques exemples supplémentaires. Dans un environnement B2B, un fabricant commande des articles à un fournisseur et reçoit à son tour une facture. La facture contiendra plusieurs lignes d'articles, chacune d'elles indiquant la quantité et l'article fourni ; par exemple, des morceaux de tuyaux de 5 pouces x 200, etc. Dans cette situation, les articles et les factures ont une relation plusieurs-à-plusieurs (réfléchissez-y et convainquez votreself). Dans un système de gestion de flotte, les véhicules et les conducteurs entretiendront une relation similaire. Dans un site de commerce électronique, les utilisateurs et les produits peuvent entretenir une relation plusieurs-à-plusieurs si l'on considère des fonctionnalités telles que les favoris ou les listes de souhaits.

Très bien, maintenant comment créerate cette relation plusieurs-à-plusieurs en SQL ? Sur la base de notre connaissance du fonctionnement de la relation un-à-plusieurs, il pourrait être tentant de penser que nous devrions stocker les clés étrangères de l'autre table dans les deux tables. Cependant, nous nous heurtons à des problèmes majeurs si nous essayons de le faire. Jetez un œil à cet exemple où les livres et les auteurs sont censés avoir une relation plusieurs-à-plusieurs :

À première vue, tout va bien - les livres sont mappés aux auteurs exactement de manière plusieurs-à-plusieurs. Mais regardez attentivement le authors données de table: les identifiants 12 et 13 du livre sont tous deux écrits par Peter M. (identifiant auteur 2), à cause de quoi nous n'avons d'autre choix que de répéter les entrées. Non seulement le authors table a maintenant des problèmes d'intégrité des données ( normalisation et tout ça), les valeurs dans le id Les colonnes se répètent maintenant. Cela signifie que dans la conception que nous avons choisie, il ne peut y avoir aucune colonne de clé primaire (car les clés primaires ne peuvent pas avoir de doubles).ate valeurs), et tout s’écroule.

De toute évidence, nous avons besoin d’une nouvelle façon de procéder et, heureusement, ce problème a déjà été résolu. Étant donné que le stockage des clés étrangères directement dans les deux tables gâche les choses, la bonne façon de créer des relations plusieurs-à-plusieurs dans un SGBDR consiste à créer ce qu'on appelle une « table de jointure ». L'idée est basiqueally laisser les deux tables d'origine intactes et créerate a third table pour démontrerate le mappage plusieurs-à-plusieurs.

Refaisons l'exemple qui a échoué pour contenir une table de jointure:

Notez qu'il y a eu des changements drastiques:

  • Le nombre de colonnes dans le authors la table est réduite.
  • Le nombre de colonnes dans le books la table est réduite.
  • Le nombre de rows dans le authors table est réduite car il n'y a plus besoin de répétition.
  • Une nouvelle table appelée authors_books est apparu, contenant des informations sur l'ID d'auteur associé à l'ID de livre. Nous aurions pu nommer n'importe quoi à la table de jointure, mais par convention, c'est le résultat de simplement joindre les deux tables qu'elle représente, en utilisant un trait de soulignement.

La table de jointure n'a pas de clé primaire et, dans la plupart des cas, ne contient que deux colonnes - ID des deux tables. C'est presque comme si nous supprimions les colonnes de clé étrangère de notre exemple précédent et les collions dans cette nouvelle table. Puisqu'il n'y a pas de clé primaire, il peut y avoir autant de répétitions que nécessaire pour enregistrer toutes les relations.

Maintenant, nous pouvons voir de nos yeux comment la table de jointure affiche clairement les relations, mais comment y accéder dans nos applications? Le secret est lié au nom - joindre table. Ce n'est pas un cours sur les requêtes SQL, donc je ne vais pas y plonger mais l'idée est que si vous voulez tous les livres d'un auteur particulier dans une seule requête efficace, vous joignez les tables en SQL dans le même ordre -> authors, authors_bookset booksL’ authors et le authors_books les tables sont jointes sur id et le author_id colonnes, respectivement, tandis que le authors_books et le books les tables sont jointes sur le book_id et le id colonnes, respectivement.

Épuisant, oui. Mais regardez le bon côté - nous avons fini TOUTE la théorie/le travail de base nécessaire que nous devions faire avant d'aborder les modèles Eloquents. Et laissez-moi vous rappeler que tout cela n’est pas facultatif ! Ne pas connaître la conception de la base de données vous laissera dans une confusion éloquente.reveuh. De plus, quoiatever Eloquent fait ou essaie de faire, mirrors parfaitement ces détails au niveau de la base de données, il est donc facile de comprendre pourquoi essayer d'apprendre Eloquent tout en fuyant le SGBDR est un exercice futile.

Création de relations de modèle dans Laravel Eloquent

finally, après un détour de quelque 70,000 XNUMX milles, nous sommes arrivés au point où nous pouvons parler d'Eloquent, de ses modèles et de la façon de créerate/Utilise les. Maintenant, nous avons appris dans le prevpartie intéressante de l'article selon laquelle tout commence par la base de données et la façon dont vous modélisez vos données. Cela m'a fait réaliser que je devais utiliser un exemple unique et complet pour démarrer un nouveau projet. En même temps, je veux que cet exemple soit du monde réel, et non pas sur des blogs et des auteurs ou des livres et des étagères (qui sont aussi du monde réel, mais ont été faits à mort).

Imaginons un magasin qui vend des peluches. Supposons également que nous ayons reçu le document d'exigences, à partir duquel nous pouvons identifier ces quatre entités dans le système : utilisateurs, commandes, factures, articles, etc.ategories, subcategories et transactions. Oui, il y aura probablement plus de complications, mais mettons cela de côté et concentrons-nous sur la façon dont nous passons d'un document à une application.

Une fois identifiées les principales entités du système, il faut réfléchir à la manière dont elles relate les uns aux autres, en termes de relations avec les bases de données dont nous avons discuté jusqu'à présent. Voici ceux auxquels je peux penser :

  • Utilisateurs et commandes: un à plusieurs.
  • Commandes et factures: une à une. Je me rends compte que celui-ci n'est pas coupé et séché, et selon votre domaine d'activité, il peut y avoir une relation un à plusieurs, plusieurs à un ou plusieurs à plusieurs. Mais en ce qui concerne votre petit magasin de commerce électronique moyen, une commande ne donnera lieu qu'à une seule facture et vice versa.
  • Commandes et articles: plusieurs à plusieurs.
  •  Articles et Categories : Plusieurs contre un. Encore une fois, ce n’est pas le cas sur les grands sites de commerce électronique, mais nous avons une petite opération.
  • Categories et Subcategories : un à plusieurs. Encore une fois, vous trouverez la plupart des exemples concrets qui contredisent cela, mais bon, Eloquent est déjà assez difficile comme ça, alors ne rendons pas la modélisation des données plus difficile !
  • Commandes et transactions : une à plusieurs. J'aimerais également ajouter ces deux points pour justifier mon choix : 1) Nous aurions également pu ajouter une relation entre les transactions et les factures. C'est juste une décision de modélisation des données. 2) Pourquoi un à plusieurs ici ? Eh bien, il est courant qu'un paiement de commande échoue pour une raison quelconque et réussisse la prochaine fois. Dans ce cas, nous avons deux transactions crééesated pour cette commande. Que nous souhaitions ou non afficher ces transactions ayant échoué est une décision commerciale, mais c'est toujours une bonne idée de capturer des données précieuses.

Y a-t-il d'autres relations ? Eh bien, bien d’autres relations sont possibles, mais elles ne sont pas pratiques. Par exemple, nous pouvons dire qu’un utilisateur effectue de nombreuses transactions, il devrait donc y avoir une relation entre elles. Ce qu'il faut comprendre ici, c'est qu'il existe déjà une relation indirecte : utilisateurs -> commandes -> transactions, et générateurally speaking, c'est suffisant car les SGBDR sont des bêtes pour joindre des tables. Deuxièmement, créer cette relation signifierait ajouter un user_id colonne à la transactions tableau. Si nous faisions cela pour chaque relation directe possible, nous ajouterions alors beaucoup plus de charge à la base de données (sous la forme de davantage de stockage, en particulier).ally si les UUID sont utilisés et la maintenance des index), enchaînant l'ensemble du système. Bien sûr, si l'entreprise déclare avoir besoin de données de transactions et qu'elle en a besoin dans un délai d'une seconde et demie, nous pourrions décider d'ajouter cette relation et d'accélérer les choses (compromis, compromis...).

Et maintenant, Mesdames et Messieurs, le moment est venu d'écrire le code proprement dit!

Relations du modèle Laravel - exemple réel avec code

La prochaine phase de cet article consiste à se salir les mains, mais de manière utile. Nous reprendrons les mêmes entités de base de données que dans l'exemple de commerce électronique précédent, et nous verrons comment les modèles dans Laravel sont créés.ated et connecté, dès l'installation de Laravel !

Natureally, je suppose que votre environnement de développement est configuré et que vous savez comment installer et utiliser Composer pour gérer les dépendances.

$ composer global require laravel/installer -W
$ laravel new model-relationships-study

Ces deux commandes de console installent le programme d'installation de Laravel (le -W une partie est utilisée pour la mise à niveau puisque j'avais déjà installé une ancienne version). Et au cas où vous seriez curieux, au moment d'écrire ces lignes, la version de Laravel installée est la 8.5.9. Devez-vous paniquer et effectuer une mise à niveau également ? Je le déconseille, car je n'attends pas de changements majeurs entre Laravel 5 et Laravel 8 dans le cadre de notre application. Certaines choses ont changé et le seront impact cet article (comme Model Factories), mais je pense que vous pourrez porter le code.

Puisque nous avons déjà réfléchi au modèle de données et à leurs relations, la partie relative à la création des modèles sera triviale. Et vous verrez aussi (j'ai l'air d'un disque rayé maintenant !) comment cela mirrors le schéma de la base de données car il en dépend à 100 % !

En d'autres termes, nous devons d'abord créerate les migrations (et fichiers modèles) pour tous les modèles, qui seront appliqués à la base de données. Later, on peut travailler les modèles et aborder les relations.

Alors, par quel modèle commençons-nous? Le plus simple et le moins connecté, bien sûr. Dans notre cas, cela signifie que User modèle. Puisque Laravel est livré avec ce modèle (et ne peut pas fonctionner sans lui 🤣), modifions le fichier de migration et nettoyons également le modèle pour répondre à nos besoins simples.

Voici la classe de migration:

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
        });
    }
}

Puisque nous ne sommes pas réelsally pour construire un projet, nous n'avons pas besoin d'entrer dans les mots de passe, is_active, et tout ça. Notre users table n'aura que deux colonnes: l'id et le nom de l'utilisateur.

Créonsate la migration pour Category suivant. Puisque Laravel nous offre la commodité de générerate le modèle également en une seule commande, nous en profiterons, même si nous ne toucherons pas au fichier modèle pour l'instant.

$ php artisan make:model Category -m
Model created successfully.
Created Migration: 2021_01_26_093326_create_categories_table

Et voici la classe de migration:

class CreateCategoriesTable extends Migration
{
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');
        });
    }
}

Si tu es surprisrised en l'absence du down() fonction, ne le sois pas ; dans la pratique, vous finissez rarement par l'utiliser, car la suppression d'une colonne ou d'une table ou la modification d'un type de colonne entraîne une perte de données irrécupérables. En développement, vous trouverez votreself supprimer la base de données entière, puis réexécuter les migrations. Mais nous nous éloignons du sujet, alors revenons en arrière et abordons l'entité suivante. Depuis le subcateles gories sont directement related à categories, je pense que c'est une bonne idée de faire ça ensuite.

$ php artisan make:model SubCategory -m
Model created successfully.
Created Migration: 2021_01_26_140845_create_sub_categories_table

Très bien, maintenant remplissons le fichier de migration:

class CreateSubCategoriesTable extends Migration
{
    public function up()
    {
        Schema::create('sub_categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');

            $table->unsignedBigInteger('category_id');
            $table->foreign('category_id')
                ->references('id')
                ->on('categories')
                ->onDelete('cascade');
        });
    }
}

Comme vous pouvez le voir, nous ajoutons un séparateurate colonne ici, appelée category_id, qui stockera les identifiants du categories tableau. Aucun prix pour deviner, cette créationatec'est une relation un à plusieurs au niveau de la base de données.

C'est maintenant au tour des objets:

$ php artisan make:model Item -m
Model created successfully.
Created Migration: 2021_01_26_141421_create_items_table

Et la migration:

class CreateItemsTable extends Migration
{
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->string('type');
            $table->unsignedInteger('price');
            $table->unsignedInteger('quantity_in_stock');

            $table->unsignedBigInteger('sub_category_id');
            $table->foreign('sub_category_id')
                ->references('id')
                ->on('sub_categories')
                ->onDelete('cascade');
        });
    }
}

Si vous pensez que les choses devraient être faites différemment, c'est très bien. Deux personnes auront rarement le même schéma et la même architecture. Notez une chose, qui est une bonne pratique en quelque sorte: j'ai stocké le prix sous forme d'entier.

Pourquoi ?

Eh bien, les gens ont réalisé que la manipulation float divisions et tout était moche et sujet aux erreurs du côté de la base de données, ils ont donc commencé à stocker le prix en termes de la plus petite unité monétaire. Par exemple, si nous opérons en USD, le champ de prix ici représenterait des centimes. Dans tout le système, les valeurs et les calculs seront en centimes ; ce n'est que lorsqu'il sera temps de l'afficher à l'utilisateur ou d'envoyer un PDF par email que nous diviserons par 100 et arrondirons. Cleverhein?

Quoi qu'il en soit, notez qu'un élément est lié à un subcatesanglant dans une relation à plusieurs. C'est aussi lié à l'acatesanglant. . . indirectement via son subcatesanglant. Nous verrons de solides démonstrations de toute cette gymnastique, mais pour l'instant, nous devons apprécierate les concepts et assurez-vous que nous sommes clairs à 100%.

La prochaine étape est la Order modèle et sa migration:

$ php artisan make:model Order -m
Model created successfully.
Created Migration: 2021_01_26_144157_create_orders_table

Pour le bien de brevity, je n'inclurai que certains des domaines importants dans la migration. J'entends par là que les détails d'une commande peuvent contenir un grand nombre de choses, mais nous les limiterons à quelques-unes afin de pouvoir nous concentrer sur le concept de relations modèles.

class CreateOrdersTable extends Migration
{
    public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->string('status');
            $table->unsignedInteger('total_value');
            $table->unsignedInteger('taxes');
            $table->unsignedInteger('shipping_charges');

            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');
        });
    }
}

Ça a l'air bien, mais attendez une minute ! Où sont les articles dans cet ordre ? Comme nous l'avons établi précédemment, il existe une relation plusieurs-à-plusieurs entre les commandes et les articles, donc une simple clé étrangère ne fonctionne pas. La solution est ce qu'on appelle une table de jonction ou intermédiaireate tableau. En d’autres termes, nous avons besoin d’une table de jointure pour stocker le mappage plusieurs-à-plusieurs entre les commandes et les articles. Désormais, dans le monde Laravel, il existe une convention intégrée que nous suivons pour gagner du temps : si je créeate une nouvelle table en utilisant le singular forme des deux noms de table, placez-les dans l'ordre du dictionnaire et joignez-les à l'aide d'un trait de soulignement, Laravel le fera automatiquementally reconnaissez-le comme la table de réunion.

Dans notre cas, la table de jonction sera appelée item_order (le mot « article » précède « commande » dans un dictionnaire). De plus, comme expliqué précédemment, cette table de jonction normaliseraally ne contiennent que deux colonnes, des clés étrangères à chaque table.

Nous pourrions créerate un modèle + migration ici, mais le modèle ne sera jamais utilisé car il s'agit plutôt d'une méta-chose. Ainsi, nous créonsate une nouvelle migration dans Laravel et dites-lui quoi.

$ php artisan make:migration create_item_order_table --create="item_order"
Created Migration: 2021_01_27_093127_create_item_order_table

Cela se traduit par une nouvelle migration, que nous modifierons comme suit:

class CreateItemOrderTable extends Migration
{
    public function up()
    {
        Schema::create('item_order', function (Blueprint $table) {
            $table->unsignedBigInteger('order_id');
            $table->foreign('order_id')
                ->references('id')
                ->on('orders')
                ->onDelete('cascade');
            
            $table->unsignedBigInteger('item_id');
            $table->foreign('item_id')
                ->references('id')
                ->on('items')
                ->onDelete('cascade');    
        });
    }
}

Comment agirally accéder à ces relations via des appels de méthode Eloquent est un sujet pour later, mais notez que nous devons d'abord minutieusement, à la main, créerate ces clés étrangères. Sans cela, il n'y a pas d'Eloquent et il n'y a pas de « intelligent » dans Laravel. 🙂

Sommes-nous déjà là? Enfin presque. . .

Nous n'avons plus que quelques modèles à craindre. Le premier est le tableau des factures, et vous vous souviendrez que nous avons décidé d'en faire une relation individuelle avec les commandes.

$ php artisan make:model Invoice -m
Model created successfully.
Created Migration: 2021_01_27_101116_create_invoices_table

Dans les toutes premières sections de cet article, nous avons vu qu'une façon d'imposer une relation un-à-un consiste à faire de la clé primaire de la table enfant la clé étrangère également. Dans la pratique, presque personne n’adopte cette approche trop prudente, et les gensally concevoir le schéma comme ils le feraient pour une relation un-à-plusieurs. Mon point de vue est qu’une approche intermédiaire est préférable ; rendez simplement la clé étrangère unique et vous vous êtes assuré que les identifiants du modèle parent ne peuvent pas être répétésated:

class CreateInvoicesTable extends Migration
{
    public function up()
    {
        Schema::create('invoices', function (Blueprint $table) {
            $table->id();
            $table->timestamp('raised_at')->nullable();
            $table->string('status');
            $table->unsignedInteger('totalAmount');

            $table->unsignedBigInteger('order_id')->unique();
            $table->foreign('order_id')
                ->references('id')
                ->on('orders')
                ->onDelete('cascade')
                ->unique();
        });
    }
}

Et oui, pour la énième fois, je suis conscient qu'il manque beaucoup à ce tableau des factures ; cependant, notre objectif ici est de voir comment les relations de modèle fonctionnent et non pour concevoir une base de données entière.

Ok, donc nous avons atteint le point où nous devons créerate la migration finale de notre système (j'espère !). L'accent est désormais mis sur Transaction modèle, que nous avons décidé plus tôt est lié au Order modèle. En passant, voici un exercice pour vous: si le Transaction le modèle soit plutôt lié au Invoice modèle? Pourquoi et pourquoi pas? 🙂

$ php artisan make:model Transaction -m
Model created successfully.
Created Migration: 2021_01_31_145806_create_transactions_table

Et la migration:

class CreateTransactionsTable extends Migration
{
    public function up()
    {
        Schema::create('transactions', function (Blueprint $table) {
            $table->id();
            $table->timestamp('executed_at');
            $table->string('status');
            $table->string('payment_mode');
            $table->string('transaction_reference')->nullable();

            $table->unsignedBigInteger('order_id');
            $table->foreign('order_id')
                ->references('id')
                ->on('orders')
                ->onDelete('cascade');
        });
    }
}

Phew! C'était un travail difficile. . . exécutons les migrations et voyons comment nous nous en sortons aux yeux de la base de données.

$ php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (3.45ms)
Migrating: 2021_01_26_093326_create_categories_table
Migrated:  2021_01_26_093326_create_categories_table (2.67ms)
Migrating: 2021_01_26_140845_create_sub_categories_table
Migrated:  2021_01_26_140845_create_sub_categories_table (3.83ms)
Migrating: 2021_01_26_141421_create_items_table
Migrated:  2021_01_26_141421_create_items_table (6.09ms)
Migrating: 2021_01_26_144157_create_orders_table
Migrated:  2021_01_26_144157_create_orders_table (4.60ms)
Migrating: 2021_01_27_093127_create_item_order_table
Migrated:  2021_01_27_093127_create_item_order_table (3.05ms)
Migrating: 2021_01_27_101116_create_invoices_table
Migrated:  2021_01_27_101116_create_invoices_table (3.95ms)
Migrating: 2021_01_31_145806_create_transactions_table
Migrated:  2021_01_31_145806_create_transactions_table (3.54ms)

Louange au Seigneur! 🙏🏻🙏🏻 On dirait que nous avons survécu au moment du procès.

Et avec cela, nous sommes prêts à passer à la définition des relations modèles ! Pour cela, nous devons revenir à la liste que nous avons créée.ated plus tôt, décrivant le type de relations directes entre les modèles (tableaux).

Pour commencer, nous avons établi qu'il existe une relation un-à-plusieurs entre les utilisateurs et les commandes. Nous pouvons le confirmer en allant dans le fichier de migration des commandes et en voyant la présence du champ user_id là. Ce champ est ce que créeatec'est la relation, car toute relation que nous souhaitons établir doit d'abord être honorée par la base de données ; le reste (syntaxe éloquente et où écrire quelle fonction) n'est qu'une pure formalité.

En d'autres termes, la relation est déjà là. Nous devons simplement dire à Eloquent de le rendre disponible au moment de l'exécution. Commençons par le Order modèle, où nous déclarons qu'il appartient au User modèle:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    use HasFactory;

    public function user() {
        return $this->belongsTo(User::class);
    }
}

La syntaxe doit vous être familière; nous déclarons une fonction nommée user(), qui sert à accéder à l'utilisateur propriétaire de cette commande (le nom de la fonction peut être n'importe quoi ; c'est ce qu'elle renvoie qui compte). Repensez-y un instant : s'il n'y avait pas de base de données ni de clés étrangères, un statement comme $this->belongsTo n'aurait aucun sens. C'est uniquement parce qu'il y a une clé étrangère sur le orders table que Laravel est capable d'utiliser user_id rechercher l'utilisateur avec le même id et retournez-le. Par celaself, sans la coopération de la base de données, Laravel ne peut pas créerate des relations à partir de rien.

Maintenant, ce serait aussi nice être capable d'écrire $user->orders pour accéder aux commandes d'un utilisateur. Cela signifie que nous devons aller au User modélisez et écrivez une fonction pour la partie «plusieurs» de cette relation un-à-plusieurs:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasFactory;
    public $timestamps = false;

    public function orders() {
        return $this->hasMany(Order::class);
    }
}

Oui, j'ai fortement modifié la valeur par défaut User model car nous n'avons pas besoin de toutes les autres fonctionnalités pour ce didacticiel. Quoi qu'il en soit, le User class a maintenant une méthode appelée orders(), qui dit qu'un utilisateur peut être associéated avec plusieurs commandes. Dans le monde ORM, on dit que le orders() relation ici est l'inverse de la user() relation que nous avions sur le Order .

Mais attendez une minute! Comment fonctionne cette relation? Je veux dire, il n'y a rien au niveau de la base de données qui ait plusieurs connexions sortant du users table à la orders tableau.

Acteally, Là is une connexion existante, et il s'avère que cela suffit à lui seul - la référence de clé étrangère stockée dans le orders table! C'est, quand nous disons quelque chose comme $user->orders, Laravel frappe le orders() fonction et sait en le regardant qu'il y a une clé étrangère sur le orders table. Ensuite, ça fait un peu SELECT * FROM orders WHERE user_id = 23 et renvoie les résultats de la requête sous forme de collection. Bien sûr, tout l'intérêt d'avoir un ORM est d'oublier SQL, mais nous ne devons pas oublier complètement que la base sous-jacente est le SGBDR qui exécute les requêtes SQL.

Ensuite, passons en revue les modèles de commandes et de factures, dans lesquels nous entretenons une relation individuelle:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    use HasFactory;
    public $timestamps = false;

    public function user() {
        return $this->belongsTo(User::class);
    }

    public function invoice() {
        return $this->hasOne(Invoice::class);
    }
}

Et le modèle de facture:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model
{
    use HasFactory;
    public $timestamps = false;

    public function order() {
        return $this->belongsTo(Order::class);
    }
}

Notez qu'au niveau de la base de données, ainsi que presque au niveau éloquent, c'est une relation un-à-plusieurs typique; nous venons d'ajouter quelques vérifications pour nous assurer qu'il reste un à un.

Nous arrivons maintenant à un autre type de relation : la relation plusieurs-à-plusieurs entre les commandes et les articles. Rappelons que nous avons déjà created un intermédiaireate table appelée item_order qui stocke le mappage entre les clés primaires. Si tout a été fait correctement, définir la relation et travailler avec elle est trivial. Selon la documentation Laravel, pour définir une relation plusieurs-à-plusieurs, vos méthodes doivent renvoyer un belongsToMany() exemple.

Donc, dans le Item modèle:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;
    public $timestamps = false;

    public function orders() {
        return $this->belongsToMany(Order::class);
    }
}

Étonnamment, la relation inverse est presque identique:

class Order extends Model
{
    /* ... other code */
    
    public function items() {
        return $this->belongsToMany(Item::class);
    }
}

Et c'est tout! Tant que nous avons suivi correctement les conventions de dénomination, Laravel est capable de déduire les mappages ainsi que leur emplacement.

Puisque les trois types fondamentaux de relations ont été abordés (un-à-un, un-à-plusieurs, plusieurs-à-plusieurs), j'arrêterai d'écrire les méthodes pour d'autres modèles, car elles le seront tout au long du processus. mêmes lignes. Créons plutôtate les usines pour ces modèles, create quelques données factices, et voyez ces relations en action !

Comment fait-on cela? Eh bien, prenons le chemin rapide et sale et jetons tout dans le fichier de semoir par défaut. Ensuite, lorsque nous exécuterons les migrations, nous exécuterons également le semeur. Alors, voici ce que mon DatabaseSeeder.php le fichier ressemble à:

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Category;
use App\Models\SubCategory;
use App\Models\Item;
use App\Models\Order;
use App\Models\Invoice;
use App\Models\User;
use Faker;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $faker = Faker\Factory::create();

        // Let's make two users
        $user1 = User::create(['name' => $faker->name]);
        $user2 = User::create(['name' => $faker->name]);

        // Create two categories, each having two subcategories
        $category1 = Category::create(['name' => $faker->word]);
        $category2 = Category::create(['name' => $faker->word]);

        $subCategory1 = SubCategory::create(['name' => $faker->word, 'category_id' => $category1->id]);
        $subCategory2 = SubCategory::create(['name' => $faker->word, 'category_id' => $category1->id]);

        $subCategory3 = SubCategory::create(['name' => $faker->word, 'category_id' => $category2->id]);
        $subCategory4 = SubCategory::create(['name' => $faker->word, 'category_id' => $category2->id]);

        // After categories, well, we have items
        // Let's create two items each for sub-category 2 and 4
        $item1 = Item::create([
            'sub_category_id' => 2,
            'name' => $faker->name,
            'description' => $faker->text,
            'type' => $faker->word,
            'price' => $faker->randomNumber(2),
            'quantity_in_stock' => $faker->randomNumber(2),
        ]);

        $item2 = Item::create([
            'sub_category_id' => 2,
            'name' => $faker->name,
            'description' => $faker->text,
            'type' => $faker->word,
            'price' => $faker->randomNumber(3),
            'quantity_in_stock' => $faker->randomNumber(2),
        ]);

        $item3 = Item::create([
            'sub_category_id' => 4,
            'name' => $faker->name,
            'description' => $faker->text,
            'type' => $faker->word,
            'price' => $faker->randomNumber(4),
            'quantity_in_stock' => $faker->randomNumber(2),
        ]);

        $item4 = Item::create([
            'sub_category_id' => 4,
            'name' => $faker->name,
            'description' => $faker->text,
            'type' => $faker->word,
            'price' => $faker->randomNumber(1),
            'quantity_in_stock' => $faker->randomNumber(3),
        ]);

        // Now that we have users and items, let's make user1 place a couple of orders
        $order1 = Order::create([
            'status' => 'confirmed',
            'total_value' => $faker->randomNumber(3),
            'taxes' => $faker->randomNumber(1),
            'shipping_charges' => $faker->randomNumber(2),
            'user_id' => $user1->id
        ]);

        $order2 = Order::create([
            'status' => 'waiting',
            'total_value' => $faker->randomNumber(3),
            'taxes' => $faker->randomNumber(1),
            'shipping_charges' => $faker->randomNumber(2),
            'user_id' => $user1->id
        ]);

        // now, assigning items to orders
        $order1->items()->attach($item1);
        $order1->items()->attach($item2);
        $order1->items()->attach($item3);
        
        $order2->items()->attach($item1);
        $order2->items()->attach($item4);

        // and finally, create invoices
        $invoice1 = Invoice::create([
            'raised_at' => $faker->dateTimeThisMonth(),
            'status' => 'settled',
            'totalAmount' => $faker->randomNumber(3),
            'order_id' => $order1->id,
        ]);
    }
}

Et maintenant, nous configurons à nouveau la base de données et la semons:

$ php artisan migrate:fresh --seed
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (43.81ms)
Migrating: 2021_01_26_093326_create_categories_table
Migrated:  2021_01_26_093326_create_categories_table (2.20ms)
Migrating: 2021_01_26_140845_create_sub_categories_table
Migrated:  2021_01_26_140845_create_sub_categories_table (4.56ms)
Migrating: 2021_01_26_141421_create_items_table
Migrated:  2021_01_26_141421_create_items_table (5.79ms)
Migrating: 2021_01_26_144157_create_orders_table
Migrated:  2021_01_26_144157_create_orders_table (6.40ms)
Migrating: 2021_01_27_093127_create_item_order_table
Migrated:  2021_01_27_093127_create_item_order_table (4.66ms)
Migrating: 2021_01_27_101116_create_invoices_table
Migrated:  2021_01_27_101116_create_invoices_table (6.70ms)
Migrating: 2021_01_31_145806_create_transactions_table
Migrated:  2021_01_31_145806_create_transactions_table (6.09ms)
Database seeding completed successfully.

D'accord! Voici la dernière partie de cet article, où nous accédons simplement à ces relations et confirmons tout ce que nous avons appris jusqu'à présent. Vous serez ravi de savoir (j'espère) que ce sera une section légère et amusante.

Et maintenant, lançons le composant le plus amusant de Laravel - la console interactive Tinker!

$ php artisan tinker
Psy Shell v0.10.6 (PHP 8.0.0 — cli) by Justin Hileman
>>>

Accéder aux relations de modèle un-à-un dans Laravel Eloquent

Bon, alors, tout d'abord, accédons à la relation individuelle que nous avons dans nos modèles de commande et de facture:

>>> $order = Order::find(1);
[!] Aliasing 'Order' to 'App\Models\Order' for this Tinker session.
=> App\Models\Order {#4108
     id: 1,
     status: "confirmed",
     total_value: 320,
     taxes: 5,
     shipping_charges: 12,
     user_id: 1,
   }
>>> $order->invoice
=> App\Models\Invoice {#4004
     id: 1,
     raised_at: "2021-01-21 19:20:31",
     status: "settled",
     totalAmount: 314,
     order_id: 1,
   }

Vous remarquez quelque chose ? N'oubliez pas que, de la manière dont cela a été fait au niveau de la base de données, cette relation est de un à plusieurs, si ce n'est pour le extra contraintes. Ainsi, Laravel aurait pu renvoyer une collection d'objets (ou un seul objet) comme résultat, et ce serait techniqueally précisate. MAIS . . . nous avons dit à Laravel qu'il s'agit d'une relation un-à-un, le résultat est donc une seule instance Eloquent. Remarquez comment la même chose se produit lors de l'accès à la relation inverse :

$invoice = Invoice::find(1);
[!] Aliasing 'Invoice' to 'App\Models\Invoice' for this Tinker session.
=> App\Models\Invoice {#3319
     id: 1,
     raised_at: "2021-01-21 19:20:31",
     status: "settled",
     totalAmount: 314,
     order_id: 1,
   }
>>> $invoice->order
=> App\Models\Order {#4042
     id: 1,
     status: "confirmed",
     total_value: 320,
     taxes: 5,
     shipping_charges: 12,
     user_id: 1,
   }

Accéder aux relations de modèle un-à-plusieurs dans Laravel Eloquent

Nous avons une relation un-à-plusieurs entre les utilisateurs et les commandes. «Bricolons» maintenant et voyons le résultat:

>>> User::find(1)->orders;
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#4291
     all: [
       App\Models\Order {#4284
         id: 1,
         status: "confirmed",
         total_value: 320,
         taxes: 5,
         shipping_charges: 12,
         user_id: 1,
       },
       App\Models\Order {#4280
         id: 2,
         status: "waiting",
         total_value: 713,
         taxes: 4,
         shipping_charges: 80,
         user_id: 1,
       },
     ],
   }
>>> Order::find(1)->user
=> App\Models\User {#4281
     id: 1,
     name: "Dallas Kshlerin",
   }

Exactement comme prévu, l'accès aux commandes d'un utilisateur aboutit à une collection d'enregistrements, tandis que l'inverse ne produit qu'un seul User objet. En d'autres termes, un-à-plusieurs.

Accéder aux relations de modèles plusieurs-à-plusieurs dans Laravel Eloquent

Maintenant, explorons une relation plusieurs-à-plusieurs. Nous avons une telle relation entre les articles et les commandes:

>>> $item1 = Item::find(1);
[!] Aliasing 'Item' to 'App\Models\Item' for this Tinker session.
=> App\Models\Item {#4253
     id: 1,
     name: "Russ Kutch",
     description: "Deserunt voluptatibus omnis ut cupiditate doloremque. Perspiciatis officiis odio et accusantium alias aut. Voluptatum provident aut ut et.",
     type: "adipisci",
     price: 26,
     quantity_in_stock: 65,
     sub_category_id: 2,
   }
>>> $order1 = Order::find(1);
=> App\Models\Order {#4198
     id: 1,
     status: "confirmed",
     total_value: 320,
     taxes: 5,
     shipping_charges: 12,
     user_id: 1,
   }
>>> $order1->items
=> Illuminate\Database\Eloquent\Collection {#4255
     all: [
       App\Models\Item {#3636
         id: 1,
         name: "Russ Kutch",
         description: "Deserunt voluptatibus omnis ut cupiditate doloremque. Perspiciatis officiis odio et accusantium alias aut. Voluptatum provident aut ut et.",
         type: "adipisci",
         price: 26,
         quantity_in_stock: 65,
         sub_category_id: 2,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4264
           order_id: 1,
           item_id: 1,
         },
       },
       App\Models\Item {#3313
         id: 2,
         name: "Mr. Green Cole",
         description: "Maxime beatae porro commodi fugit hic. Et excepturi natus distinctio qui sit qui. Est non non aut necessitatibus aspernatur et aspernatur et. Voluptatem possimus consequatur exercitationem et.",
         type: "pariatur",
         price: 381,
         quantity_in_stock: 82,
         sub_category_id: 2,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4260
           order_id: 1,
           item_id: 2,
         },
       },
       App\Models\Item {#4265
         id: 3,
         name: "Brianne Weissnat IV",
         description: "Delectus ducimus quia voluptas fuga sed eos esse. Rerum repudiandae incidunt laboriosam. Ea eius omnis autem. Cum pariatur aut voluptas sint aliquam.",
         type: "non",
         price: 3843,
         quantity_in_stock: 26,
         sub_category_id: 4,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4261
           order_id: 1,
           item_id: 3,
         },
       },
     ],
   }
>>> $item1->orders
=> Illuminate\Database\Eloquent\Collection {#4197
     all: [
       App\Models\Order {#4272
         id: 1,
         status: "confirmed",
         total_value: 320,
         taxes: 5,
         shipping_charges: 12,
         user_id: 1,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4043
           item_id: 1,
           order_id: 1,
         },
       },
       App\Models\Order {#4274
         id: 2,
         status: "waiting",
         total_value: 713,
         taxes: 4,
         shipping_charges: 80,
         user_id: 1,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4257
           item_id: 1,
           order_id: 2,
         },
       },
     ],
   }

Cette sortie peut être un bit vertigineux à lire, mais remarquez que item1 fait partie des éléments de order1, et vice versa, c'est ainsi que nous configurons les choses. Jetons également un coup d'œil aux intermédiairesate table qui stocke les mappages :

>>> use DB;
>>> DB::table('item_order')->select('*')->get();
=> Illuminate\Support\Collection {#4290
     all: [
       {#4270
         +"order_id": 1,
         +"item_id": 1,
       },
       {#4276
         +"order_id": 1,
         +"item_id": 2,
       },
       {#4268
         +"order_id": 1,
         +"item_id": 3,
       },
       {#4254
         +"order_id": 2,
         +"item_id": 1,
       },
       {#4267
         +"order_id": 2,
         +"item_id": 4,
       },
     ],
   }

Conclusion

Oui, c'est ça, really! Ça a été une récidiveally article long, mais j'espère qu'il a été utile. Est-ce tout ce qu’il faut savoir sur les modèles Laravel ?

Malheureusement non. Le lapinbit le trou est really, réally profond, et il existe de nombreux concepts plus difficiles tels que les relations polymorphes et l'optimisation des performances, et ainsi de suite, que vous rencontrerez en grow en tant que développeur Laravel. Pour l'instant, ce que couvre cet article est suffisant pour 70 % des développeurs, 70 % du temps, soit environ XNUMX % du temps.peaking. Ce sera really bien avant que vous ressentiez le besoin de mettre à niveau vos connaissances.

Avec cette mise en garde, je veux que vous reteniez cette idée la plus importante: rien n'est de la magie noire ou hors de portée programmation. C'est seulement que nous ne comprenons pas les fondations et comment les choses sont construites, ce qui nous rend difficile et frustré.ated.

Donc . . . ?

Investissez dans votreself! Cours, livres, articles, autres communautés de programmation (Python est ma recommandation n°1) — utilisez whateVous pouvez trouver et consommer régulièrement des ressources, même si lentement. Bientôt, le nombre de cas où vous risquez de tout gâcher diminuera considérablement.ally.

Bon, assez de prédication. Avoir un nice jour! 🙂

Partager sur:
  • Ankush
    Auteur
    J'écris sur, autour et pour le développeur ecossystème. Recommandations, tutoriels, discussions techniques — whateAu fur et à mesure que je publie, je fais de mon mieux pour éliminer la confusion et le fluff, et fournir des réponses exploitables basées sur mon expérience personnelle…

Merci à nos commanditaires

Plus de bonnes lectures sur le développement

Alimentez votre entreprise

Certains des outils et services pour aider votre entreprise grow.
  • L'outil de synthèse vocale qui utilise l'IA pour générerate des voix humaines réalistes.

    Essayez Murf AI
  • Web scraping, proxy résidentiel, proxy manager, web unlocker, moteur de recherche et tout ce dont vous avez besoin pour collecter des données Web.

    Essayez Brightdata
  • Monday.com est un système d'exploitation de travail tout-en-un pour vous aider à gérer les projets, les tâches, le travail, les ventes, le CRM, les opérations, workflowset plus encore.

    Essayez Monday
  • Intruder est un scanner de vulnérabilités en ligne qui détecte les failles de cybersécurité de votre infrastructure, afin d'éviter des violations de données coûteuses.

    Essayez Intruder