使用 Lighthouse 构建 GraphQL 服务器的入门,从零开始为一个简单博客创建 GraphQL API
1、使用 Lighthouse 构建 GraphQL 服务器的入门。参考网址:https://lighthouse-php.cn/tutorial/
2、从零开始为一个简单博客创建 GraphQL API。通过 Composer 创建一个新的 Laravel 项目:lighthouse-tutorial
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | PS E:\wwwroot> composer create-project laravel/laravel lighthouse-tutorial Creating a "laravel/laravel" project at "./lighthouse-tutorial" Installing laravel/laravel (v8.6.10) - Installing laravel/laravel (v8.6.10): Extracting archive Created project in E:\wwwroot\lighthouse-tutorial > @php -r "file_exists('.env') || copy('.env.example', '.env');" Loading composer repositories with package information Updating dependencies Lock file operations: 110 installs, 0 updates, 0 removals - Locking asm89/stack-cors (v2.0.5) - Locking brick/math (0.9.3) - Locking dflydev/dot-access-data (v3.0.1) - Locking doctrine/inflector (2.0.4) - Locking doctrine/instantiator (1.4.0) - Locking doctrine/lexer (1.2.1) - Locking dragonmantank/cron-expression (v3.2.3) - Locking egulias/email-validator (2.1.25) - Locking facade/flare-client-php (1.9.1) - Locking facade/ignition (2.17.4) - Locking facade/ignition-contracts (1.0.2) - Locking fakerphp/faker (v1.17.0) - Locking filp/whoops (2.14.5) - Locking fruitcake/laravel-cors (v2.0.5) - Locking graham-campbell/result-type (v1.0.4) - Locking guzzlehttp/guzzle (7.4.1) - Locking guzzlehttp/promises (1.5.1) - Locking guzzlehttp/psr7 (2.1.0) - Locking hamcrest/hamcrest-php (v2.0.1) - Locking laravel/framework (v8.78.1) - Locking laravel/sail (v1.12.12) - Locking laravel/sanctum (v2.13.0) - Locking laravel/serializable-closure (v1.0.5) - Locking laravel/tinker (v2.6.3) - Locking league/commonmark (2.1.1) - Locking league/config (v1.1.1) - Locking league/flysystem (1.1.9) - Locking league/mime-type-detection (1.9.0) - Locking mockery/mockery (1.4.4) - Locking monolog/monolog (2.3.5) - Locking myclabs/deep-copy (1.10.2) - Locking nesbot/carbon (2.55.2) - Locking nette/schema (v1.2.2) - Locking nette/utils (v3.2.6) - Locking nikic/php-parser (v4.13.2) - Locking nunomaduro/collision (v5.11.0) - Locking opis/closure (3.6.2) - Locking phar-io/manifest (2.0.3) - Locking phar-io/version (3.1.0) - Locking phpdocumentor/reflection-common (2.2.0) - Locking phpdocumentor/reflection-docblock (5.3.0) - Locking phpdocumentor/type-resolver (1.6.0) - Locking phpoption/phpoption (1.8.1) - Locking phpspec/prophecy (v1.15.0) - Locking phpunit/php-code-coverage (9.2.10) - Locking phpunit/php-file-iterator (3.0.6) - Locking phpunit/php-invoker (3.1.1) - Locking phpunit/php-text-template (2.0.4) - Locking phpunit/php-timer (5.0.3) - Locking phpunit/phpunit (9.5.11) - Locking psr/container (1.1.2) - Locking psr/event-dispatcher (1.0.0) - Locking psr/http-client (1.0.1) - Locking psr/http-factory (1.0.1) - Locking psr/http-message (1.0.1) - Locking psr/log (1.1.4) - Locking psr/simple-cache (1.0.1) - Locking psy/psysh (v0.10.12) - Locking ralouphie/getallheaders (3.0.3) - Locking ramsey/collection (1.2.2) - Locking ramsey/uuid (4.2.3) - Locking sebastian/cli-parser (1.0.1) - Locking sebastian/code-unit (1.0.8) - Locking sebastian/code-unit-reverse-lookup (2.0.3) - Locking sebastian/comparator (4.0.6) - Locking sebastian/complexity (2.0.2) - Locking sebastian/diff (4.0.4) - Locking sebastian/environment (5.1.3) - Locking sebastian/exporter (4.0.4) - Locking sebastian/global-state (5.0.3) - Locking sebastian/lines-of-code (1.0.3) - Locking sebastian/object-enumerator (4.0.4) - Locking sebastian/object-reflector (2.0.4) - Locking sebastian/recursion-context (4.0.4) - Locking sebastian/resource-operations (3.0.3) - Locking sebastian/type (2.3.4) - Locking sebastian/version (3.0.2) - Locking swiftmailer/swiftmailer (v6.3.0) - Locking symfony/console (v5.4.2) - Locking symfony/css-selector (v5.4.2) - Locking symfony/deprecation-contracts (v2.5.0) - Locking symfony/error-handler (v5.4.2) - Locking symfony/event-dispatcher (v5.4.0) - Locking symfony/event-dispatcher-contracts (v2.5.0) - Locking symfony/finder (v5.4.2) - Locking symfony/http-foundation (v5.4.2) - Locking symfony/http-kernel (v5.4.2) - Locking symfony/mime (v5.4.2) - Locking symfony/polyfill-ctype (v1.24.0) - Locking symfony/polyfill-iconv (v1.24.0) - Locking symfony/polyfill-intl-grapheme (v1.24.0) - Locking symfony/polyfill-intl-idn (v1.24.0) - Locking symfony/polyfill-intl-normalizer (v1.24.0) - Locking symfony/polyfill-mbstring (v1.24.0) - Locking symfony/polyfill-php72 (v1.24.0) - Locking symfony/polyfill-php73 (v1.24.0) - Locking symfony/polyfill-php80 (v1.24.0) - Locking symfony/polyfill-php81 (v1.24.0) - Locking symfony/process (v5.4.2) - Locking symfony/routing (v5.4.0) - Locking symfony/service-contracts (v2.5.0) - Locking symfony/string (v5.4.2) - Locking symfony/translation (v5.4.2) - Locking symfony/translation-contracts (v2.5.0) - Locking symfony/var-dumper (v5.4.2) - Locking theseer/tokenizer (1.2.1) - Locking tijsverkoyen/css-to-inline-styles (2.2.4) - Locking vlucas/phpdotenv (v5.4.1) - Locking voku/portable-ascii (1.5.6) - Locking webmozart/assert (1.10.0) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 110 installs, 0 updates, 0 removals - Downloading nunomaduro/collision (v5.11.0) - Installing doctrine/inflector (2.0.4): Extracting archive - Installing doctrine/lexer (1.2.1): Extracting archive - Installing symfony/polyfill-ctype (v1.24.0): Extracting archive - Installing webmozart/assert (1.10.0): Extracting archive - Installing dragonmantank/cron-expression (v3.2.3): Extracting archive - Installing symfony/polyfill-php80 (v1.24.0): Extracting archive - Installing symfony/polyfill-mbstring (v1.24.0): Extracting archive - Installing symfony/var-dumper (v5.4.2): Extracting archive - Installing symfony/polyfill-intl-normalizer (v1.24.0): Extracting archive - Installing symfony/polyfill-intl-grapheme (v1.24.0): Extracting archive - Installing symfony/string (v5.4.2): Extracting archive - Installing symfony/deprecation-contracts (v2.5.0): Extracting archive - Installing psr/container (1.1.2): Extracting archive - Installing symfony/service-contracts (v2.5.0): Extracting archive - Installing symfony/polyfill-php73 (v1.24.0): Extracting archive - Installing symfony/console (v5.4.2): Extracting archive - Installing psr/log (1.1.4): Extracting archive - Installing monolog/monolog (2.3.5): Extracting archive - Installing voku/portable-ascii (1.5.6): Extracting archive - Installing phpoption/phpoption (1.8.1): Extracting archive - Installing graham-campbell/result-type (v1.0.4): Extracting archive - Installing vlucas/phpdotenv (v5.4.1): Extracting archive - Installing symfony/css-selector (v5.4.2): Extracting archive - Installing tijsverkoyen/css-to-inline-styles (2.2.4): Extracting archive - Installing symfony/routing (v5.4.0): Extracting archive - Installing symfony/process (v5.4.2): Extracting archive - Installing symfony/polyfill-php72 (v1.24.0): Extracting archive - Installing symfony/polyfill-intl-idn (v1.24.0): Extracting archive - Installing symfony/mime (v5.4.2): Extracting archive - Installing symfony/http-foundation (v5.4.2): Extracting archive - Installing psr/event-dispatcher (1.0.0): Extracting archive - Installing symfony/event-dispatcher-contracts (v2.5.0): Extracting archive - Installing symfony/event-dispatcher (v5.4.0): Extracting archive - Installing symfony/error-handler (v5.4.2): Extracting archive - Installing symfony/http-kernel (v5.4.2): Extracting archive - Installing symfony/finder (v5.4.2): Extracting archive - Installing symfony/polyfill-iconv (v1.24.0): Extracting archive - Installing egulias/email-validator (2.1.25): Extracting archive - Installing swiftmailer/swiftmailer (v6.3.0): Extracting archive - Installing symfony/polyfill-php81 (v1.24.0): Extracting archive - Installing ramsey/collection (1.2.2): Extracting archive - Installing brick/math (0.9.3): Extracting archive - Installing ramsey/uuid (4.2.3): Extracting archive - Installing psr/simple-cache (1.0.1): Extracting archive - Installing opis/closure (3.6.2): Extracting archive - Installing symfony/translation-contracts (v2.5.0): Extracting archive - Installing symfony/translation (v5.4.2): Extracting archive - Installing nesbot/carbon (2.55.2): Extracting archive - Installing league/mime-type-detection (1.9.0): Extracting archive - Installing league/flysystem (1.1.9): Extracting archive - Installing nette/utils (v3.2.6): Extracting archive - Installing nette/schema (v1.2.2): Extracting archive - Installing dflydev/dot-access-data (v3.0.1): Extracting archive - Installing league/config (v1.1.1): Extracting archive - Installing league/commonmark (2.1.1): Extracting archive - Installing laravel/serializable-closure (v1.0.5): Extracting archive - Installing laravel/framework (v8.78.1): Extracting archive - Installing facade/ignition-contracts (1.0.2): Extracting archive - Installing facade/flare-client-php (1.9.1): Extracting archive - Installing facade/ignition (2.17.4): Extracting archive - Installing fakerphp/faker (v1.17.0): Extracting archive - Installing asm89/stack-cors (v2.0.5): Extracting archive - Installing fruitcake/laravel-cors (v2.0.5): Extracting archive - Installing psr/http-message (1.0.1): Extracting archive - Installing psr/http-client (1.0.1): Extracting archive - Installing ralouphie/getallheaders (3.0.3): Extracting archive - Installing psr/http-factory (1.0.1): Extracting archive - Installing guzzlehttp/psr7 (2.1.0): Extracting archive - Installing guzzlehttp/promises (1.5.1): Extracting archive - Installing guzzlehttp/guzzle (7.4.1): Extracting archive - Installing laravel/sail (v1.12.12): Extracting archive - Installing laravel/sanctum (v2.13.0): Extracting archive - Installing nikic/php-parser (v4.13.2): Extracting archive - Installing psy/psysh (v0.10.12): Extracting archive - Installing laravel/tinker (v2.6.3): Extracting archive - Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive - Installing mockery/mockery (1.4.4): Extracting archive - Installing filp/whoops (2.14.5): Extracting archive - Installing nunomaduro/collision (v5.11.0): Extracting archive - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive - Installing phpdocumentor/type-resolver (1.6.0): Extracting archive - Installing phpdocumentor/reflection-docblock (5.3.0): Extracting archive - Installing sebastian/version (3.0.2): Extracting archive - Installing sebastian/type (2.3.4): Extracting archive - Installing sebastian/resource-operations (3.0.3): Extracting archive - Installing sebastian/recursion-context (4.0.4): Extracting archive - Installing sebastian/object-reflector (2.0.4): Extracting archive - Installing sebastian/object-enumerator (4.0.4): Extracting archive - Installing sebastian/global-state (5.0.3): Extracting archive - Installing sebastian/exporter (4.0.4): Extracting archive - Installing sebastian/environment (5.1.3): Extracting archive - Installing sebastian/diff (4.0.4): Extracting archive - Installing sebastian/comparator (4.0.6): Extracting archive - Installing sebastian/code-unit (1.0.8): Extracting archive - Installing sebastian/cli-parser (1.0.1): Extracting archive - Installing phpunit/php-timer (5.0.3): Extracting archive - Installing phpunit/php-text-template (2.0.4): Extracting archive - Installing phpunit/php-invoker (3.1.1): Extracting archive - Installing phpunit/php-file-iterator (3.0.6): Extracting archive - Installing theseer/tokenizer (1.2.1): Extracting archive - Installing sebastian/lines-of-code (1.0.3): Extracting archive - Installing sebastian/code-unit-reverse-lookup (2.0.3): Extracting archive - Installing phpunit/php-code-coverage (9.2.10): Extracting archive - Installing doctrine/instantiator (1.4.0): Extracting archive - Installing phpspec/prophecy (v1.15.0): Extracting archive - Installing phar-io/version (3.1.0): Extracting archive - Installing phar-io/manifest (2.0.3): Extracting archive - Installing myclabs/deep-copy (1.10.2): Extracting archive - Installing phpunit/phpunit (9.5.11): Extracting archive 70 package suggestions were added by new dependencies, use `composer suggest` to see details. Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead. Generating optimized autoload files > Illuminate\Foundation\ComposerScripts::postAutoloadDump > @php artisan package:discover --ansi Discovered Package: facade/ignition Discovered Package: fruitcake/laravel-cors Discovered Package: laravel/sail Discovered Package: laravel/sanctum Discovered Package: laravel/tinker Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully. 77 packages you are using are looking for funding. Use the `composer fund` command to find out more! > @php artisan vendor:publish --tag=laravel-assets --ansi --force No publishable resources for tag [laravel-assets]. Publishing complete. > @php artisan key:generate --ansi Application key set successfully. |
3、创建数据库:lighthouse_tutorial,配置 .env 中的数据库连接。运行数据库迁移以创建 users 表
1 2 3 4 5 6 7 8 9 10 | PS E:\wwwroot\lighthouse-tutorial> php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (42.37ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (36.39ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (40.11ms) Migrating: 2019_12_14_000001_create_personal_access_tokens_table Migrated: 2019_12_14_000001_create_personal_access_tokens_table (53.85ms) |
4、在数据库中植入一些假的用户数据。factory(‘App\User’, 10)->create(); 在 Laravel 8 已经不可用。需要使用 User::factory()->count(10)->create();。如图1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | PS E:\wwwroot\lighthouse-tutorial> php artisan tinker Psy Shell v0.10.12 (PHP 7.4.27 — cli) by Justin Hileman >>> factory('App\User', 10)->create(); PHP Fatal error: Call to undefined function factory() in Psy Shell code on line 1 >>> App\Factory('App\User', 10)->create(); PHP Fatal error: Call to undefined function App\Factory() in Psy Shell code on line 1 >>> User::factory()->count(50)->create(); [!] Aliasing 'User' to 'App\Models\User' for this Tinker session. => Illuminate\Database\Eloquent\Collection {#3581 all: [ App\Models\User {#3585 name: "Ashton Tremblay", email: "letha42@example.net", email_verified_at: "2022-01-12 05:51:41", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "k1o1mrmP7o", updated_at: "2022-01-12 05:51:41", created_at: "2022-01-12 05:51:41", id: 1, }, App\Models\User {#3592 name: "Rene Powlowski", email: "hkovacek@example.org", email_verified_at: "2022-01-12 05:51:41", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "64Cl19QXs3", updated_at: "2022-01-12 05:51:41", created_at: "2022-01-12 05:51:41", id: 2, }, ... ], } >>> |
5、安装 Lighthouse,将使用 Lighthouse 作为 GraphQL 服务器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | PS E:\wwwroot\lighthouse-tutorial> composer require nuwave/lighthouse Using version ^5.35 for nuwave/lighthouse ./composer.json has been updated Running composer update nuwave/lighthouse Loading composer repositories with package information Updating dependencies Lock file operations: 5 installs, 0 updates, 0 removals - Locking haydenpierce/class-finder (0.4.3) - Locking laragraph/utils (v1.1.1) - Locking nuwave/lighthouse (v5.35.0) - Locking thecodingmachine/safe (v1.3.3) - Locking webonyx/graphql-php (v14.11.3) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 5 installs, 0 updates, 0 removals - Downloading nuwave/lighthouse (v5.35.0) - Installing webonyx/graphql-php (v14.11.3): Extracting archive - Installing thecodingmachine/safe (v1.3.3): Extracting archive - Installing laragraph/utils (v1.1.1): Extracting archive - Installing haydenpierce/class-finder (0.4.3): Extracting archive - Installing nuwave/lighthouse (v5.35.0): Extracting archive 6 package suggestions were added by new dependencies, use `composer suggest` to see details. Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead. Generating optimized autoload files > Illuminate\Foundation\ComposerScripts::postAutoloadDump > @php artisan package:discover --ansi Discovered Package: facade/ignition Discovered Package: fruitcake/laravel-cors Discovered Package: laravel/sail Discovered Package: laravel/sanctum Discovered Package: laravel/tinker Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Discovered Package: nuwave/lighthouse Package manifest generated successfully. 79 packages you are using are looking for funding. Use the `composer fund` command to find out more! > @php artisan vendor:publish --tag=laravel-assets --ansi --force No publishable resources for tag [laravel-assets]. Publishing complete. PS E:\wwwroot\lighthouse-tutorial> |
6、使用 Altair GraphQL Client 作为 GraphQL 查询的 IDE (在线调试工具)。它就好像 GraphQL 专用的 Postman,拥有很多神奇的功能。在 Chrome 浏览器的网上应用商店中搜索:GraphQL,排名第一的就是。如图2
7、将默认模式发布到 graphql/schema.graphql。报错:No publishable resources for tag [schema].
1 2 3 4 | PS E:\wwwroot\lighthouse-tutorial> php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema No publishable resources for tag [schema]. Publishing complete. PS E:\wwwroot\lighthouse-tutorial> |
8、建议参考英文的最新文档:https://lighthouse-php.com/tutorial 。将默认模式发布到 graphql/schema.graphql。发布完成。
1 2 3 4 | PS E:\wwwroot\lighthouse-tutorial> php artisan vendor:publish --tag=lighthouse-schema Copied File [\vendor\nuwave\lighthouse\src\default-schema.graphql] To [\graphql\schema.graphql] Publishing complete. PS E:\wwwroot\lighthouse-tutorial> |
9、在 Nginx 中配置虚拟主机:lighthouse-tutorial.local 。在 Altair GraphQL Client 中打开网址:http://lighthouse-tutorial.local/graplql 。如图3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | server { listen 80; server_name lighthouse-tutorial.local; root E:/wwwroot/lighthouse-tutorial/public; access_log logs/lighthouse-tutorial.local.access.log; error_log logs/lighthouse-tutorial.local.error.log; add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { # fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } |
请求:
1 2 3 4 5 6 7 8 9 | query{ user(id: 1){ id name email created_at updated_at } } |
响应:
1 2 3 4 5 6 7 8 9 10 11 | { "data": { "user": { "id": "1", "name": "Ashton Tremblay", "email": "letha42@example.net", "created_at": "2022-01-12 05:51:41", "updated_at": "2022-01-12 05:51:41" } } } |
10、为我们的 posts 和 comments 定义模型和迁移。运行迁移。将 posts 模型添加到 app/User.php。
11、The Schema,修改 graphql/schema.graphql 并根据我们创建的有说服力的模型来定义我们的 posts 的模式。我们添加了两个用于查询文章到 Query 类型的最后面。 @all 返回所有内容的列表 Post 模型 。 @find 和 @eq 是通过其 ID 组合检索单个 Post。我们还可以通过添加额外的类型定义,明确定义我们的数据模型。如图4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | "A date string with format `Y-m-d`, e.g. `2011-05-23`." scalar Date @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date") "A datetime string with format `Y-m-d H:i:s`, e.g. `2018-05-23 13:43:32`." scalar DateTime @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime") type Query { users: [User!]! @paginate(defaultCount: 10) user(id: ID @eq): User @find posts: [Post!]! @all post(id: Int! @eq): Post @find } type User { id: ID! name: String! email: String! created_at: DateTime! updated_at: DateTime! posts: [Post!]! @hasMany } type Post { id: ID! title: String! content: String! author: User! @belongsTo comments: [Comment!]! @hasMany } type Comment { id: ID! reply: String! post: Post! @belongsTo } |
12、最终测试,在你的数据库中插入一些假数据,你可以使用 Laravel seeders 来完成。编辑模型工厂文件:database/factories/PostFactory.php、database/factories/CommentFactory.php。
database/factories/PostFactory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; use App\Models\Post; class PostFactory extends Factory { protected $model = Post:: class ; /** * Define the model's default state. * * @return array */ public function definition() { $sentence = $this ->faker->sentence(); return [ 'author_id' => rand(1, 100), 'title' => $sentence , 'content' => $this ->faker->text(), ]; } } |
database/factories/CommentFactory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; use App\Models\Comment; class CommentFactory extends Factory { protected $model = Comment:: class ; /** * Define the model's default state. * * @return array */ public function definition() { return [ 'post_id' => rand(1, 100), 'reply' => $this ->faker->sentence(), ]; } } |
13、完成数据工厂的定制后,接下来我们开始书写填充部分。编辑数据填充文件:database/seeders/UsersTableSeeder.php、database/seeders/PostsTableSeeder.php、database/seeders/CommentsTableSeeder.php。
database/seeders/UsersTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\User; class UsersTableSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { User::factory()-> count (100)->create(); } } |
database/seeders/PostsTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\Post; class PostsTableSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { Post::factory()-> count (100)->create(); } } |
database/seeders/CommentsTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\Comment; class CommentsTableSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { Comment::factory()-> count (100)->create(); } } |
14、注册数据填充。编辑 database/seeders/DatabaseSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace Database\Seeders; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this ->call(UsersTableSeeder:: class ); $this ->call(PostsTableSeeder:: class ); $this ->call(CommentsTableSeeder:: class ); } } |
15、执行数据填充命令:php artisan migrate:refresh –seed,报错:Call to undefined method App\Models\Post::factory()。如图5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | PS E:\wwwroot\lighthouse-tutorial> php artisan migrate:refresh --seed Rolling back: 2022_01_12_062416_create_comments_table Rolled back: 2022_01_12_062416_create_comments_table (16.76ms) Rolling back: 2022_01_12_062104_create_posts_table Rolled back: 2022_01_12_062104_create_posts_table (8.20ms) Rolling back: 2019_12_14_000001_create_personal_access_tokens_table Rolled back: 2019_12_14_000001_create_personal_access_tokens_table (9.17ms) Rolling back: 2019_08_19_000000_create_failed_jobs_table Rolled back: 2019_08_19_000000_create_failed_jobs_table (8.87ms) Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (9.72ms) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (7.01ms) Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (28.61ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (31.30ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (31.69ms) Migrating: 2019_12_14_000001_create_personal_access_tokens_table Migrated: 2019_12_14_000001_create_personal_access_tokens_table (39.67ms) Migrating: 2022_01_12_062104_create_posts_table Migrated: 2022_01_12_062104_create_posts_table (17.16ms) Migrating: 2022_01_12_062416_create_comments_table Migrated: 2022_01_12_062416_create_comments_table (20.25ms) Seeding: Database\Seeders\UsersTableSeeder Seeded: Database\Seeders\UsersTableSeeder (1,839.80ms) Seeding: Database\Seeders\PostsTableSeeder BadMethodCallException Call to undefined method App\Models\Post::factory() at E:\wwwroot\lighthouse-tutorial\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php:71 67▕ * @throws \BadMethodCallException 68▕ */ 69▕ protected static function throwBadMethodCallException($method) 70▕ { ➜ 71▕ throw new BadMethodCallException(sprintf( 72▕ 'Call to undefined method %s::%s()', static::class, $method 73▕ )); 74▕ } 75▕ } • Bad Method Call: Did you mean App\Models\Post::author() ? 1 E:\wwwroot\lighthouse-tutorial\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php:36 Illuminate\Database\Eloquent\Model::throwBadMethodCallException("factory") 2 E:\wwwroot\lighthouse-tutorial\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php:2132 Illuminate\Database\Eloquent\Model::forwardCallTo(Object(Illuminate\Database\Eloquent\Builder), "factory", []) PS E:\wwwroot\lighthouse-tutorial> |
16、编辑数据模型文件,app/Models/Post.php、app/Models/Comment.php,引入 HasFactory。
app/Models/Post.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Post extends Model { use HasFactory; public function author(): BelongsTo { return $this ->belongsTo(User:: class , 'author_id' ); } public function comments(): HasMany { return $this ->hasMany(Comment:: class ); } } |
app/Models/Comment.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Comment extends Model { use HasFactory; public function post(): BelongsTo { return $this ->belongsTo(Post:: class ); } } |
17、执行数据填充成功后,访问 /graphql 并尝试以下的查询。获取到数据库中所有 posts 的列表,以及全部 comments 和 user 的 name。符合预期。如图6
请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 | query { posts { id title author { name } comments { id reply } } } |
响应:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | { "data": { "posts": [ { "id": "1", "title": "Optio earum deserunt fuga qui quia hic.", "author": { "name": "Mrs. Lottie Kuhlman IV" }, "comments": [] }, { "id": "2", "title": "Soluta eius quisquam consequatur accusantium distinctio minima.", "author": { "name": "Otilia Marvin" }, "comments": [] }, { "id": "3", "title": "Unde harum commodi rerum nam dolores vel eligendi.", "author": { "name": "Alfreda Crooks" }, "comments": [ { "id": "14", "reply": "Laborum exercitationem odit voluptas cumque adipisci." } ] }, { "id": "4", "title": "Praesentium iste nisi aut reprehenderit aliquam.", "author": { "name": "Hassan Goyette MD" }, "comments": [] }, { "id": "5", "title": "Atque illo consequatur eveniet.", "author": { "name": "Estevan Mann" }, "comments": [] }, { "id": "6", "title": "Praesentium et eaque soluta.", "author": { "name": "Prof. Rosalia Cartwright Sr." }, "comments": [ { "id": "5", "reply": "Omnis doloremque tempore ut laboriosam nihil." } ] }, { "id": "7", "title": "Assumenda consequatur quo perspiciatis reiciendis.", "author": { "name": "Nestor Bauch" }, "comments": [ { "id": "70", "reply": "Error quia natus inventore aliquid praesentium et." } ] }, { "id": "8", "title": "Nesciunt eos enim minus ipsa non sed minus.", "author": { "name": "Reggie Batz" }, "comments": [ { "id": "22", "reply": "Magnam et cum reiciendis et." } ] }, { "id": "9", "title": "In et quasi dolorem aliquam nemo sequi.", "author": { "name": "Carroll Cartwright" }, "comments": [ { "id": "73", "reply": "Cumque harum id officiis eum cumque." } ] }, { "id": "10", "title": "Consequatur modi enim fugit ut eos.", "author": { "name": "Kiley Connelly" }, "comments": [ { "id": "71", "reply": "Aut harum fuga quos veniam quia perspiciatis." }, { "id": "90", "reply": "Harum unde debitis sunt sint tenetur temporibus voluptates." } ] }, ... ] } } |
18、随机选择 posts 的 id 等于 10 的数据验证,响应与数据库中一致。如图7
近期评论