(1)获取结果集

最后更新于:2022-04-02 01:42:32

[TOC] ## 获取所有行:`DB` facade 的 `get` 方法 `get` 方法可以获取表中所有记录: ~~~php get(); return view('user.index', ['users' => $users]); } } ~~~ `get` 方法会返回一个 `Illuminate\Support\Collection` 结果集,其中每个结果都是一个 PHP 的`StdClass` 对象实例。可以像访问对象的属性一样访问字段的值: ~~~php foreach ($users as $user) { echo $user->name; } ~~~ ## 获取单个行或列:`DB` facade 的 `first` 或 `value` 方法 `first` 方法只从数据表中获取一行数据 ,返回单个 `StdClass` 对象: ~~~php $user = DB::table('users')->where('name', 'John')->first(); echo $user->name; ~~~ `value` 方法来从单条记录中取出单个值。此方法将直接返回字段的值: ~~~php $email = DB::table('users')->where('name', 'John')->value('email'); ~~~ ## 获取一列的值:`DB` facade 的 `pluck` 方法 `pluck` 方法获取一个包含单个字段值的集合 。在下面的例子中,我们将取出 `roles` 表中 `title` 字段的集合: ~~~php $titles = DB::table('roles')->pluck('title'); foreach ($titles as $title) { echo $title; } ~~~ 还可以在返回数组中为列值指定自定义键(该自定义键必须是该表的其它字段列名,否则会报错): ~~~php $roles = DB::table('roles')->pluck('title', 'name'); foreach ($roles as $name => $title) { echo $title; } ~~~
';

第五节 DB 数据库查询构建器

最后更新于:2022-04-02 01:42:30

Laravel 的数据库查询构造器 `DB` facade 提供了一个方便、流畅的接口来创建及运行数据库查询语句。它能用来执行应用程序中的大部分数据库操作,且能在所有被支持的数据库系统中使用。 Laravel 的查询构造器使用 PDO 参数绑定来避免 SQL 注入攻击,因此绑定的字符串传入时,不需要额外转义特殊字符进行过滤。 以下小节将使用一个临时的控制器文件,位于 `app/Http/Controllers` 目录下的 `UserController.php`,来演示如何使用查询构造器操作用户表 `users`。 ## 创建查询实例:`DB` facade 的 `table` 方法 `table` 方法可以为指定表返回一个流式查询构建器实例,该实例可以在查询上链接多个约束条件,并最终返回查询结果。 以下是 `UserController.php` 文件的基本结构: ~~~php get(); // 打印数据 dd($users); // return view('user.index', ['users' => $users]); } } ~~~ >[info] 辅助函数 `dd()` 相当于 `dump and die`,可以将输出的数据格式化,便于查看。
';

第四节 Seeding 数据填充

最后更新于:2022-04-02 01:42:28

暂略。
';

(3) 索引操作

最后更新于:2022-04-02 01:42:26

[TOC] ## 索引创建 ### 创建唯一索引 1. 在字段定义后,链式调用 `unique` 方法来创建索引: ~~~php $table->string('email')->unique(); ~~~ 2. 也可以在定义完所有字段之后,单独创建索引: ~~~php $table->unique('email'); ~~~ ### 创建复合索引 传递一个包含字段名的数组至索引方法: ~~~php $table->index(['account_id', 'created_at']); ~~~ ### 自定义索引名称 Laravel 会自动生成一个合理的索引名称,但也可以使用第二个参数来自定义: ~~~php $table->index('email', 'my_index_name'); ~~~ ### 可用的索引类型 命令 | 描述 ------------- | ------------- `$table->primary('id');` | 添加主键。 `$table->primary(['first', 'last']);` | 添加复合键。 `$table->unique('email');` | 添加唯一索引。 `$table->unique('state', 'my_index_name');` | 自定义索引名称。 `$table->unique(['first', 'last']);` | 添加复合唯一键。 `$table->index('state');` | 添加基本索引。 ### 配置索引长度 Laravel 默认使用 `utf8mb4` 字符,可支持在数据库里存储「表情」。 如果你使用的 **MySQL 版本低于 5.7.7** 或 **MariaDB 版本低于 10.2.2**,你可能需要手动配置默认字符串长度,以顺利创建索引。 方法是修改 `app/Providers/AppServiceProvider.php` 文件,调用 `Schema::defaultStringLength` 方法: ~~~php use Illuminate\Support\Facades\Schema; /** * Bootstrap any application services. * 引导任何应用程序服务。 * * @return void */ public function boot() { Schema::defaultStringLength(191); } ~~~ 或者你可以为数据库开启 `innodb_large_prefix` 选项,有关如何正确开启此选项的说明请查阅数据库文档。 ## 索引移除 >[danger] 若要移除索引,则**必须**指定索引的名称。 ### 传递完整的索引名称字符串 >[info] Laravel 默认会自动给索引分配合理的名称:数据表名称_索引的字段名称_索引类型。 命令 | 描述 ------------- | ------------- `$table->dropPrimary('users_id_primary');` | 从「users」数据表移除主键。 `$table->dropUnique('users_email_unique');` | 从「users」数据表移除唯一索引。 `$table->dropIndex('geo_state_index');` | 从「geo」数据表移除基本索引。 ### 传递包含字段名的数组 >[info] 索引名称将由 数据表名 和 字段名 拼接而成 ~~~php Schema::table('geo', function (Blueprint $table) { $table->dropIndex(['state']); // 移除索引 'geo_state_index' }); ~~~ ## 外键约束 ### 创建外键约束 有 `user_id` 字段的 `posts` 数据表,`user_id` 引用了 `users` 数据表的 `id` 字段: ~~~php Schema::table('posts', function (Blueprint $table) { $table->integer('user_id')->unsigned(); $table->foreign('user_id')->references('id')->on('users'); }); ~~~ ### 指定外键约束的「on delete」及「on update」行为 ~~~php $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); ~~~ ### 移除外键约束: `dropForeign` 方法 #### 传递完整的外键约束名称字符串 >[info] 外键约束与索引采用相同的命名方式:数据表名称_约束字段_foreign。 ~~~php $table->dropForeign('posts_user_id_foreign'); ~~~ #### 传递一个包含字段名的数组 ~~~php $table->dropForeign(['user_id']); ~~~ > 在移除的时候,字段会按照惯例被自动转换为对应的外键名称。 #### 在迁移文件里开启和关闭外键约束 ~~~php // 开启 Schema::enableForeignKeyConstraints(); // 关闭 Schema::disableForeignKeyConstraints(); ~~~
';

(2) 字段操作

最后更新于:2022-04-02 01:42:23

[TOC] ## 字段创建 `CreateUsersTable` 类中通过 `Blueprint` 实例 `$table` 为 users 表创建所需的字段: > 由 `increments` 方法创建一个` integer` 类型的自增长 id。 ~~~php $table->increments('id'); ~~~ > 由 `string` 方法创建一个 `name` 字段,用于保存用户名称。 ~~~php $table->string('name'); ~~~ > 由 `string` 方法创建一个 `email` 字段,且在最后指定该字段的值为唯一值,用于保存用户邮箱。 ~~~php $table->string('email')->unique(); ~~~ > 由 `string` 方法创建一个 `password` 字段,且在 `string` 方法中指定保存的值最大长度为 60,用于保存用户密码。 ~~~php $table->string('password', 60); ~~~ > 由 `rememberToken` 方法为用户创建一个 `remember_token` 字段,用于保存『记住我』的相关信息。 ~~~php $table->rememberToken(); ~~~ > 由 `timestamps` 方法创建了一个 `created_at` 和一个 `updated_at` 字段,分别用于保存用户的创建时间和更新时间。 ~~~php $table->timestamps(); ~~~ >[info] 该迁移文件最终生成的数据表如下: 字段名称 | 字段类型 ------------- | ------------- id | integer name | string email | string password | string remember_token | string created_at | datetime updated_at | datetime ### 可用的字段类型 命令 | 描述 ------------- | ------------- `$table->bigIncrements('id');` | 递增 ID(主键),相当于「UNSIGNED BIG INTEGER」型态。 `$table->bigInteger('votes');` | 相当于 BIGINT 型态。 `$table->binary('data');` | 相当于 BLOB 型态。 `$table->boolean('confirmed');` | 相当于 BOOLEAN 型态。 `$table->char('name', 4);` | 相当于 CHAR 型态,并带有长度。 `$table->date('created_at');` | 相当于 DATE 型态 `$table->dateTime('created_at');` | 相当于 DATETIME 型态。 `$table->dateTimeTz('created_at');` | DATETIME (带时区) 形态 `$table->decimal('amount', 5, 2);` | 相当于 DECIMAL 型态,并带有精度与基数。 `$table->double('column', 15, 8);` | 相当于 DOUBLE 型态,总共有 15 位数,在小数点后面有 8 位数。 `$table->enum('choices', ['foo', 'bar']);` | 相当于 ENUM 型态。 `$table->float('amount', 8, 2);` | 相当于 FLOAT 型态,总共有 8 位数,在小数点后面有 2 位数。 `$table->increments('id');` | 递增的 ID (主键),使用相当于「UNSIGNED INTEGER」的型态。 `$table->integer('votes');` | 相当于 INTEGER 型态。 `$table->ipAddress('visitor');` | 相当于 IP 地址形态。 `$table->json('options');` | 相当于 JSON 型态。 `$table->jsonb('options');` | 相当于 JSONB 型态。 `$table->longText('description');` | 相当于 LONGTEXT 型态。 `$table->macAddress('device');` | 相当于 MAC 地址形态。 `$table->mediumIncrements('id');` | 递增 ID (主键) ,相当于「UNSIGNED MEDIUM INTEGER」型态。 `$table->mediumInteger('numbers');` | 相当于 MEDIUMINT 型态。 `$table->mediumText('description');` | 相当于 MEDIUMTEXT 型态。 `$table->morphs('taggable');` | 加入整数 `taggable_id` 与字符串 `taggable_type`。 `$table->nullableMorphs('taggable');` | 与 `morphs()` 字段相同,但允许为NULL。 `$table->nullableTimestamps();` | 与 `timestamps()` 相同,但允许为 NULL。 `$table->rememberToken();` | 加入 `remember_token` 并使用 VARCHAR(100) NULL。 `$table->smallIncrements('id');` | 递增 ID (主键) ,相当于「UNSIGNED SMALL INTEGER」型态。 `$table->smallInteger('votes');` | 相当于 SMALLINT 型态。 `$table->softDeletes();` | 加入 `deleted_at` 字段用于软删除操作。 `$table->string('email');` | 相当于 VARCHAR 型态。 `$table->string('name', 100);` | 相当于 VARCHAR 型态,并带有长度。 `$table->text('description');` | 相当于 TEXT 型态。 `$table->time('sunrise');` | 相当于 TIME 型态。 `$table->timeTz('sunrise');` | 相当于 TIME (带时区) 形态。 `$table->tinyInteger('numbers');` | 相当于 TINYINT 型态。 `$table->timestamp('added_on');` | 相当于 TIMESTAMP 型态。 `$table->timestampTz('added_on');` | 相当于 TIMESTAMP (带时区) 形态。 `$table->timestamps();` | 加入 `created_at` 和 `updated_at` 字段。 `$table->timestampsTz();` | 加入 `created_at` and `updated_at` (带时区) 字段,并允许为NULL。 `$table->unsignedBigInteger('votes');` | 相当于 Unsigned BIGINT 型态。 `$table->unsignedInteger('votes');` | 相当于 Unsigned INT 型态。 `$table->unsignedMediumInteger('votes');` | 相当于 Unsigned MEDIUMINT 型态。 `$table->unsignedSmallInteger('votes');` | 相当于 Unsigned SMALLINT 型态。 `$table->unsignedTinyInteger('votes');` | 相当于 Unsigned TINYINT 型态。 `$table->uuid('id');` | 相当于 UUID 型态。 ### 可用的字段修饰 除了上述的字段类型列表,还有一些其它的字段「修饰」,你可以将它增加到字段中。 例如,若要让字段「nullable」,那么你可以使用 `nullable` 方法: ~~~php Schema::table('users', function (Blueprint $table) { $table->string('email')->nullable(); }); ~~~ 修饰 | 描述 ------------- | ------------- `->after('column')` | 将此字段放置在其它字段「之后」(仅限 MySQL) `->comment('my comment')` | 增加注释 `->default($value)` | 为此字段指定「默认」值 `->first()` | 将此字段放置在数据表的「首位」(仅限 MySQL) `->nullable()` | 此字段允许写入 NULL 值 `->storedAs($expression)` | 创建一个存储的生成字段 (仅限 MySQL) `->unsigned()` | 设置 `integer` 字段为 `UNSIGNED` `->virtualAs($expression)` | 创建一个虚拟的生成字段 (仅限 MySQL) >[warning] 此列表不包括 [索引修饰](database/indexes.md) ## 字段修改 ### 先决条件 >[danger] 在修改字段之前,请**务必**在你的 `composer.json` 中增加 `doctrine/dbal` 依赖。 >[info] Doctrine DBAL 函数库: 用来判断当前字段的状态,以及创建调整指定字段的 SQL 查询。 ~~~shell $ composer require doctrine/dbal // 或修改 composer.json 文件后执行 $ composer update ~~~ ### 更改字段类型或属性:实例 `$table` 的 `change` 方法 例子: 1. 增加字符串字段的长度,把 `name` 字段的长度从 25 增加到 50 : ~~~php Schema::table('users', function (Blueprint $table) { $table->string('name', 50)->change(); }); ~~~ 2. 将字段修改为 nullable: ~~~php Schema::table('users', function (Blueprint $table) { $table->string('name', 50)->nullable()->change(); }); ~~~ >[danger] 下面的字段类型不能被「修改」: char,double,enum,mediumInteger,timestamp,tinyInteger,ipAddress,json,jsonb,macAddress,mediumIncrements,morphs,nullableMorphs,nullableTimestamps,softDeletes,timeTz,timestampTz,timestamps,timestampsTz,unsignedMediumInteger,unsignedTinyInteger,uuid。 ### 重命名字段:实例 `$table` 的 `renameColumn` 方法 ~~~php Schema::table('users', function (Blueprint $table) { $table->renameColumn('from', 'to'); }); ~~~ ### 删除字段:实例 `$table` 的 `dropColumn` 方法 ~~~php Schema::table('users', function (Blueprint $table) { $table->dropColumn('votes'); }); ~~~ #### 删除多个字段:传递多个字段的数组至 `dropCloumn` 方法 ~~~php Schema::table('users', function (Blueprint $table) { $table->dropColumn(['votes', 'avatar', 'location']); }); ~~~ >[warning] SQLite 数据库不支持在单个迁移中删除或修改多个字段。 #### 可用的删除命令 命令 | 描述 --- | --- `$table->dropRememberToken();` | 删除 `remember_token` 字段。 `$table->dropSoftDeletes();` | 删除用于软删除操作 `deleted_at` 字段。 `$table->dropSoftDeletesTz();` | 删除 `deleted_at` 字段。 `$table->dropTimestamps();` | 删除 `created_at` 和 `updated_at` 字段。 `$table->dropTimestampsTz();` | 删除 `created_at` 和 `updated_at` 字段。
';

(1) 数据表操作

最后更新于:2022-04-02 01:42:21

[TOC] ## 数据表创建:`Schema` facade 的 `create` 方法 `create` 方法接收两个参数: 1. 数据表的名称 2. 一个接收 `Blueprint` 实例 `$table` 的闭包,用于定义新数据表。 ~~~php Schema::create('users', function (Blueprint $table) { $table->increments('id'); }); ~~~ >[info] 可以使用数据库结构生成器的任何 [字段方法](database/columns.md) 来定义数据表的字段。 ### 检查数据表或字段是否存在:`Schema` facade 的 `hasTable` 和 `hasColumn` 方法 ~~~php if (Schema::hasTable('users')) { // } if (Schema::hasColumn('users', 'email')) { // } ~~~ ### 指定数据库连接:`Schema` facade 的 `connection` 方法 在非默认的数据库连接 `foo` 中进行数据库结构操作: ~~~php Schema::connection('foo')->create('users', function (Blueprint $table) { $table->increments('id'); }); ~~~ ### 指定数据表属性:在闭包里设置 命令 | 描述 --- | --- `$table->engine = 'InnoDB';` | 设置MySQL数据表的存储引擎。 `$table->charset = 'utf8';` | 设置MySQL数据表的字符集。 `$table->collation = 'utf8_unicode_ci';` | 设置MySQL数据表的排序规则。 ~~~php Schema::create('users', function (Blueprint $table) { $table->engine = 'InnoDB'; $table->increments('id'); }); ~~~ ## 数据表重命名:`Schema` facade 的 `rename` 方法 ~~~php Schema::rename($from, $to); ~~~ ### 重命名带外键的数据表 在重命名前,你需要检查[外键约束](#foreign-key-constraints)涉及到的数据表名,需要在迁移文件中显式的提供, 而不是让 Laravel 按照约定来设置一个名称。因为那样会让外键约束关联到旧的数据表上。 ## 数据表删除:`Schema` facade 的 `drop` 或 `dropIfExists` 方法 ~~~php Schema::drop('users'); Schema::dropIfExists('users'); ~~~ ## 数据表更新:`Schema` facade 的 `table` 方法 如同 `create` 方法,`table` 方法会接收两个参数: 1. 数据表的名称 2. 一个接收 `Blueprint` 实例 `$table` 的闭包,用于更新数据表。 ~~~php Schema::table('users', function (Blueprint $table) { $table->string('email'); }); ~~~ >[info] 可以使用任何数据库结构构造器的 [字段方法](database/columns.md) 来定义数据表的字段。
';

第三节 Schema 数据库结构生成器

最后更新于:2022-04-02 01:42:19

Laravel 的数据库结构生成器 `Schema` facade(门面类)提供了一种与数据库无关的方式来维护表。它在 Laravel 支持的所有数据库系统中都能很好的工作,并为这些数据库提供了统一的接口。 分三部分学习: 1. [数据表操作](database/tables.md) 2. [字段操作](database/columns.md) 3. [索引操作](database/indexes.md)
';

第二节 Migrations 数据库迁移文件

最后更新于:2022-04-02 01:42:17

本节涉及以下目录或文件: > * database/migrations [TOC] ## 迁移文件创建 ### 创建迁移文件:Artisan 命令 `make:migration` ~~~shell $ php artisan make:migration create_users_table ~~~ >[info] 所有创建的迁移文件都被统一放在 `database/migrations` 目录中。 > 每个迁移文件的名称都包含了一个 `时间戳`,以便让 Laravel 确认迁移的顺序。 ### 创建选项 #### 指定数据表的名称:`--table` 和 `--create` 选项 ~~~shell $ php artisan make:migration create_users_table --create=users $ php artisan make:migration add_votes_to_users_table --table=users ~~~ #### 指定自定义输出路径: `--path` 选项 >[warning] 提供的路径必须是相对于应用程序的基本路径。 ## 迁移文件结构 打开 `database/migrations` 文件夹可以看到,Laravel 已默认创建好了两个迁移文件: * database/migrations/2014_10_12_000000_create_users_table.php —— 用于构建 `users` 用户表 * database/migrations/2014_10_12_100000_create_password_resets_table.php —— 用于构建密码重置表 > 打开迁移实例 `database/migrations/2014_10_12_000000_create_users_table.php` ~~~php increments('id'); // 由 increments 方法创建了一个 integer 类型的自增长 id。 $table->string('name'); // 由 string 方法创建了一个 name 字段,用于保存用户名称。 $table->string('email')->unique(); // 由 string 方法创建了一个 email 字段,且在最后指定该字段的值为唯一值,用于保存用户邮箱。 $table->string('password', 60); // 由 string 方法创建了一个 password 字段,且在 string 方法中指定保存的值最大长度为 60,用于保存用户密码。 $table->rememberToken(); // 由 rememberToken 方法为用户创建一个 remember_token 字段,用于保存『记住我』的相关信息。 $table->timestamps(); // 由 timestamps 方法创建了一个 created_at 和一个 updated_at 字段,分别用于保存用户的创建时间和更新时间。 }); } /** * Reverse the migrations. * 回滚数据库迁移 * @return void */ public function down() { Schema::dropIfExists('users'); } } ~~~ 可见里面定义了一个 `CreateUsersTable` 类,并继承自 `Migration` 基类。 `CreateUsersTable` 有两个方法: 1. 运行迁移时调用的 `up` 方法:为数据库添加新的数据表、字段或索引。 2. 回滚迁移时调用的`down` 方法: `up` 方法的逆操作。 可以在这两个方法中使用 [结构生成器](database/schema.md) 来创建或修改数据表。 ## 迁移文件运行 ### 运行所有未运行过的迁移:Artisan 命令 `migrate` ~~~shell $ php artisan migrate ~~~ #### 强制运行:`--force` 选项 一些迁移的操作是具有破坏性的,它们可能会导致数据丢失。 为了保护线上环境的数据库,系统会在这些命令被运行之前显示确认提示。 若要忽略此提示并强制运行命令,则可以使用 `--force` 标记: ~~~shell $ php artisan migrate --force ~~~ ## 迁移文件回滚 ### 回滚最后一次迁移:Artisan 命令 `migrate:rollback` ~~~shell $ php artisan migrate:rollback ~~~ >[warning] 此命令是对上一次执行的「批量」迁移回滚,其中可能包括多个迁移文件。 #### 限制步数:`--step` 选项 ~~~shell $ php artisan migrate:rollback --step=5 ~~~ > 此命令将会回滚最后的 5 个迁移。 ### 回滚所有的迁移:Artisan 命令 `migrate:reset` ~~~shell $ php artisan migrate:reset ~~~ ### 回滚后重新运行迁移:Artisan 命令 `migrate:refresh` ~~~shell $ php artisan migrate:refresh // 刷新数据库结构并执行数据填充 $ php artisan migrate:refresh --seed ~~~ >[info] 此命令不仅会回滚数据库的**所有**迁移,还会接着运行 `migrate` 命令,所以可以有效的重新创建整个数据库。 #### 限制步数:`--step` 选项 ~~~shell $ php artisan migrate:refresh --step=5 ~~~ > 回滚并再迁移最后的 5 个迁移。
';

第一节 Config 数据库配置信息

最后更新于:2022-04-02 01:42:14

本节涉及以下目录或文件: > * config/database.php > * .env > * .gitignore [TOC] ## 配置文件 在 `config/database.php` 文件中,可以定义所有的数据库连接,并指定默认使用哪个连接。 默认文件内容如下: ~~~php env('DB_CONNECTION', 'mysql'), /* |-------------------------------------------------------------------------- | Database Connections | 数据库连接 |-------------------------------------------------------------------------- | | Here are each of the database connections setup for your application. | Of course, examples of configuring each database platform that is | supported by Laravel is shown below to make development simple. | | | All database work in Laravel is done through the PHP PDO facilities | so make sure you have the driver for your particular database of | choice installed on your machine before you begin development. | */ 'connections' => [ // SQLite 配置 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', ], // MySQL 配置 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ], // Postgres 配置 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', 'sslmode' => 'prefer', ], // SQL Server 配置 'sqlsrv' => [ 'driver' => 'sqlsrv', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '1433'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', ], ], /* |-------------------------------------------------------------------------- | Migration Repository Table |-------------------------------------------------------------------------- | | This table keeps track of all the migrations that have already run for | your application. Using this information, we can determine which of | the migrations on disk haven't actually been run in the database. | */ 'migrations' => 'migrations', /* |-------------------------------------------------------------------------- | Redis Databases |-------------------------------------------------------------------------- | | Redis is an open source, fast, and advanced key-value store that also | provides a richer set of commands than a typical key-value systems | such as APC or Memcached. Laravel makes it easy to dig right in. | */ 'redis' => [ 'client' => 'predis', 'default' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], ], ]; ~~~ ## 读写分离 配置一个数据库连接只用于 SELECT ,另一个用于 INSERT、UPDATE 和 DELETE ,来实现读写分离。 例子: ~~~php 'mysql' => [ 'read' => [ 'host' => '192.168.1.1', ], 'write' => [ 'host' => '196.168.1.2' ], 'sticky' => true, 'driver' => 'mysql', 'database' => 'database', 'username' => 'root', 'password' => '', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', ], ~~~ 在配置数组中新增两个键:`read` 和 `write`,这两个键对应值均为一个数组,数组内包含单个键“host”,其所映射的 IP 值分别就是读连接和写连接,读/写连接的其它数据库配置项都共用 mysql 的主数组配置。 如果我们想要覆盖主数组中的配置,只需要将相应配置项放到 `read` 和 `write` 数组中即可。在本例中,`192.168.1.1` 将被用作「读」连接,而 `192.168.1.2` 将被用作「写」连接。两个数据库连接的凭证(用户名/密码)、前缀、字符集以及其它配置将会共享 `mysql` 数组中的设置,同理,如果不一样的话,分别在 `read` 或 `write` 数组中单独配置即可。 ### 配置多个「读」连接,一个「写」连接 可以这样写: ~~~php 'mysql' => [ 'driver' => 'mysql', 'read' => [ 'host' => ['193.168.1.1', '194.168.1.1'] ], 'write' => [ 'host' => '196.168.1.2' ], ], ~~~ Laravel 在“读”数据时,会从提供的 IP 中**随机**选一个进行连接。 >[info] 实现原理可以查看 `Illuminate\Database\Connectors\ConnectionFactory` 底层源码。 >[danger] 注:目前读写分离仅支持单个「写」连接。 ### `sticky` 选项 `sticky` 是一个可选的选项,具体作用是:若在当前的请求周期内,数据库曾经被写入过一些数据,`sticky` 选项会立即将这些数据读出来。 如果 `sticky` 选项是 `true`,而且在当前的请求周期内对数据库执行过 “写入” 操作,那么任何“读取”的操作都会使用「写」连接。这样就可以确保同一个请求生命周期内写入的数据都可以立即被读取到,从而避免主从延迟导致的数据不一致,是否启用这一功能取决于你的需求。 当然,这只是一个针对分布式数据库系统中主从数据同步延迟的一个非常初级的解决方案,访问量不高的中小网站可以这么做,大流量高并发网站肯定不能这么干,主从读写分离本来就是为了解决单点性能问题,这样其实是把问题又引回去了,造成所有读写都集中到写数据库,对于高并发频繁写的场景下,后果可能是不堪设想的,但是话说回来,对于并发量不那么高,写操作不那么频繁的中小型站点来说,`sticky` 这种方式不失为一个初级的解决方案。 ## `env` 读取环境变量 在 `config/database.php` 文件中,使用了辅助函数 `evn()` 来获取环境变量,这些环境变量在项目根目录下的 `.env` 文件中定义。 `.env` 文件用以存储一些依赖环境的变量,比如数据库配置。因为它不会被加入到版本库中, 根目录下的 `.gitignore` 文件已经将其排除在外。所以还可以用来配置一些敏感信息:比如正式环境的一些第三方应用账号,token 等。 传递给 `env` 函数的第二个值是「默认值」。如果给定的环境变量不存在,则会使用该值。
';

第三章 数据库

最后更新于:2022-04-02 01:42:12

### 数据库结构 数据库迁移 Migration 的好处: 1. 多人并行开发; 2. 代码版本管理; 3. 数据库版本控制 —— 如:回滚/重置/更新等; 4. 兼容多种数据库系统; 5. 部署方便。 迁移通常会和 [结构生成器](database/schema.md) 一起使用,可以简单的管理数据库结构。 ### 数据库CURD Laravel 通过使用原始 SQL 与数据库的各种数据库进行交互, 非常简单。 数据模型- Model,利用 Laravel 提供的 Eloquent ORM 跟数据库进行交互,实现数据的增删改查操作。 Eloquent 提供了简洁优雅的 Active Record 实现来跟数据库进行交互。 Active Record 是一种领域模型模式,该模式由 Martin Fowler 在 2003 年出版的《企业应用架构模式》一书中进行了详细叙述并命名。其特点是一个模型类对应关系型数据库中的一个表,模型类的一个实例对应表中的一行记录。Active Record 最大优点是允许我们简单,直观地操作数据层。
';

总结 本章命令概览

最后更新于:2022-04-02 01:42:10

[TOC] ## 日常命令 ### 开发时监控代码更改 ~~~bash $ npm run watch-poll ~~~ ### 代码编译生成 不压缩: ~~~bash $ npm run dev ~~~ 自动压缩: ~~~bash $ npm run prod ~~~ ### Yarn & npm 常用命令 |npm | Yarn | 释义 | |---|---|---| | `npm install` | `yarn` | 安装当前项目的所有包 | | `npm install taco --save` | `yarn add taco` | taco 包被添加到 package.json 的 "dependencies" 中 | | `npm uninstall taco --save` | `yarn remove taco` | 从项目中移除 taco 包 | | `npm install taco --save-dev` | `yarn add taco --dev` | taco 包被添加到 package.json 的 "devDependencies" 中 | | `npm update --save` | `yarn upgrade` | 更新包 | >[danger] 在 Windows 下的 Homestead 虚拟机中运行时,以上命令需带 `--no-bin-links`。 >[info] 运行时需要用到的包使用 `--save`,否则使用 `--save-dev`。 > 不挂 VPN 或某些报错的情况下,可用 `cnpm` 代替 `npm`。
';

(3)运行 Mix 任务编译和监控代码

最后更新于:2022-04-02 01:42:07

注意:本节命令均需要在项目根目录下运行。 [TOC] ## 编译 >[info] 所有编译后的资源文件都被存放在 `public` 文件夹中。 ### 开发模式 >[warning] 生成的文件未被压缩,便于开发调试: ~~~bash $ npm run dev ~~~ 或 ~~~bash $ npm run developmennt ~~~ ### 生产模式 >[success] 生成的文件自动经过压缩,便于线上加载: ~~~bash $ npm run prod ~~~ 或 ~~~bash $ npm run production ~~~ ## 监控 >[info] 可在开发时一直运行,Webpack 检测到文件更改时将自动重新编译资源: ~~~bash npm run watch ~~~ 在某些环境中,当文件更改时,Webpack 不会更新。 如果系统出现这种情况,请考虑使用 `watch-poll` 命令: ~~~bash $ npm run watch-poll ~~~ ## 可能出现的报错 ### Module build failed: `node-sass` >[danger] 报错内容: ~~~bash ERROR Failed to compile with 2 errors error in ./resources/assets/sass/app.scss Module build failed: Error: ENOENT: no such file or directory, scandir '/home/vagrant/Code/Laravel/node_modules/node-sass/vendor' · · · error in ./resources/assets/sass/app.scss Module build failed: ModuleBuildError: Module build failed: Error: ENOENT: no such file or directory, scandir '/home/vagrant/Code/Laravel/node_modules/node-sass/vendor' ~~~ >[warning] 报错原因: > 打开 `~node_modules/node-sass/vendor` 文件夹下为空,缺少 `linux-x64-48/binding.node` 文件。 >[success] 解决方法: > 执行以下命令,更改包内容后进行重建 ~~~bash $ npm rebuild node-sass --no-bin-links ~~~ >[info] 成功后显示: ~~~bash Downloading binary from https://github.com/sass/node-sass/releases/download/v4.5.3/linux-x64-48_binding.node Cannot download "https://github.com/sass/node-sass/releases/download/v4.5.3/linux-x64-48_binding.node": ETIMEDOUT Timed out attemping to establish a remote connection · · · gyp info ok Installed to /home/vagrant/Code/Laravel/node_modules/node-sass/vendor/linux-x64-48/binding.node node-sass@4.5.3 /home/vagrant/Code/Laravel/node_modules/node-sass ~~~ ### Module build failed: `optipng-bin` >[danger] 报错内容: ~~~bash ERROR Failed to compile with 2 errors error in ./resources/assets/semantic/dist/themes/default/assets/images/flags.png Module build failed: Error: spawn /home/vagrant/Code/Laravel/node_modules/optipng-bin/vendor/optipng ENOENT · · · error in ./resources/assets/sass/app.scss Module build failed: ModuleBuildError: Module build failed: Error: spawn /home/vagrant/Code/Laravel/node_modules/optipng-bin/vendor/optipng ENOENT ~~~ >[warning] 报错原因: > 打开 `~node_modules/optipng-bin` 文件夹下缺少 `vendor/optipng` 文件。 >[success] 解决方法: > 执行以下命令,更改包内容后进行重建 ~~~bash $ npm rebuild optipng-bin --no-bin-links ~~~ >[info] 成功后显示: ~~~bash · · · ✔ optipng pre-build test passed successfully optipng-bin@3.1.4 /home/vagrant/Code/Laravel/node_modules/optipng-bin ~~~ ### Cannot find module 'xxxxx' >[danger] 报错内容举例: ~~~bash module.js:471 throw err; ^ Error: Cannot find module 'crypt' ~~~ >[warning] 报错原因: > 因为网络或者其他原因,导致某个扩张包没有正常安装上。 > `~node_modules` 目录下没有 `crypt` 文件夹。 >[success] 解决方法: 缺少什么包就添加什么包。 当然也可以 [清空所有扩展包,然后重新安装一遍](frontend/install-packages.md)。
';

(2)修改 resources/assets 前端资源文件

最后更新于:2022-04-02 01:42:05

应用要用到的前端资源文件(图片、JavaScript、CSS),全部位于 `resources/assets` 目录下。 该目录下有以下文件夹: > 1. js - 全部未编译的脚本文件 > 2. sass - Sass 编写的样式表文件 > 3. semantic - Semantic UI 相关文件 初次编译前可以尝试修改该目录下的以下文件。 [TOC] ## 修改 `sass/app.scss` 注释掉原有全部代码,加入以下内容 ~~~javascript // nprogress @import "~nprogress/nprogress.css"; // semantic-ui @import "../semantic/dist/semantic.css"; ~~~ ## 修改 `js/app.js` 注释掉原有关于 `vue` 的代码 ## 修改 `js/bootstrap.js` 注释掉 `require('bootstrap-sass');` 改为 ~~~javascript // semantic-ui require('../semantic/dist/semantic.js'); ~~~
';

(1)配置 webpack.mix.js 指定 Mix 任务

最后更新于:2022-04-02 01:42:03

`webpack.mix.js` 文件位于项目根目录下,是所有资源编译的入口,可以将其看作 Webpack 的轻量级**配置封装层**。Mix 任务以方法链的方式,被链在一起来定义前端资源如何被编译。 默认版如下: ~~~javascript let mix = require('laravel-mix'); /* |-------------------------------------------------------------------------- | Mix Asset Management |-------------------------------------------------------------------------- | | Mix provides a clean, fluent API for defining some Webpack build steps | for your Laravel application. By default, we are compiling the Sass | file for the application as well as bundling up all the JS files. | */ mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css'); ~~~ [TOC] ## API 概览 ~~~javascript mix.js(src, output); mix.react(src, output); // Identical to mix.js(), but registers React Babel compilation. mix.ts(src, output); // Requires tsconfig.json to exist in the same folder as webpack.mix.js mix.extract(vendorLibs); mix.sass(src, output); mix.standaloneSass('src', output); // Faster, but isolated from Webpack. mix.fastSass('src', output); // Alias for mix.standaloneSass(). mix.less(src, output); mix.stylus(src, output); mix.postCss(src, output, [require('postcss-some-plugin')()]); mix.browserSync('my-site.dev'); mix.combine(files, destination); mix.babel(files, destination); // Identical to mix.combine(), but also includes Babel compilation. mix.copy(from, to); mix.copyDirectory(fromDir, toDir); mix.minify(file); mix.sourceMaps(); // Enable sourcemaps mix.version(); // Enable versioning. mix.disableNotifications(); mix.setPublicPath('path/to/public'); mix.setResourceRoot('prefix/for/resource/locators'); mix.autoload({}); // Will be passed to Webpack's ProvidePlugin. mix.webpackConfig({}); // Override webpack.config.js, without editing the file directly. mix.then(function () {}); // Will be triggered each time Webpack finishes building. mix.options({ extractVueStyles: false, // Extract .vue component styling to file, rather than inline. globalVueStyles: file, // Variables file to be imported in every component. processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched. purifyCss: false, // Remove unused CSS selectors. uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md }); ~~~ ## 处理样式表 ### 处理 Sass `sass` 方法将 Sass 编译成 CSS。 1. 编译 `app.scss` 文件到 `public/css/app.css`: ~~~javascript mix.sass('resources/assets/sass/app.scss', 'public/css'); ~~~ 2. 多次调用 `sass` 方法可用于编译多个文件: ~~~javascript mix.sass('resources/assets/sass/app.sass', 'public/css') .sass('resources/assets/sass/admin.sass', 'public/css'); ~~~ 3. 如果要自定义编译后文件的输出位置,可以将完整的路径信息作为第二个参数传递到 `sass` 方法: ~~~javascript mix.sass('resources/assets/sass/app.sass', 'public/stylesheets/styles.css'); ~~~ * [Node-Sass 插件选项 ](https://github.com/sass/node-sass#options) 可以作为第三个参数: ~~~javascript mix.sass('resources/assets/sass/app.sass', 'public/css', { precision: 5 }); ~~~ ### 处理 Less `less` 方法将 Less 编译成 CSS。 1. 编译 `app.less` 文件到 `public/css/app.css`: ~~~javascript mix.less('resources/assets/less/app.less', 'public/css'); ~~~ 2. 和 `sass` 方法一样,也可以多次调用 `less` 方法以编译多个文件,甚至自定义结果 CSS 的输出路径: ~~~javascript mix.less('resources/assets/less/app.less', 'public/css') .less('resources/assets/less/admin.less', 'public/css/admin'); ~~~ * [Less 插件选项](https://github.com/webpack-contrib/less-loader#options) 可以作为第三个参数: ~~~javascript mix.less('resources/assets/less/app.less', 'public/css', { strictMath: true }); ~~~ ### 处理原生 CSS `styles` 方法,将多个原生 CSS 样式文件合并到一个文件: ~~~javascript mix.styles([ 'public/css/vendor/normalize.css', 'public/css/vendor/videojs.css' ], 'public/css/all.css'); ~~~ ### 资源映射 Source Map Source Map 默认被禁用,但可以通过调用 `sourceMaps` 方法来激活。 尽管这会带来编译/性能开销,不过在编译资源的时候,可以提供额外的调试信息给浏览器的开发者工具。 ~~~javascript mix.js('resources/assets/js/app.js', 'public/js') .sourceMaps(); ~~~ ## 处理脚本 Mix 还提供了多个特性来处理 JavaScript 文件,例如编译 ECMAScript 2015,模块捆绑,最小化以及合并原生 JavaScript 文件。 这些都是无缝集成的,不需要额外的自定义配置: ~~~javascript mix.js('resources/assets/js/app.js', 'public/js'); ~~~ 通过这一行代码,你可以实现如下功能: > 1. ES2015 语法 > 2. 模块 > 3. 编译 `.vue` 文件 > 4. 生产环境压缩代码 ### 提取依赖库 捆绑所有应用特定 JavaScript 和 vendor 库的一个潜在缺点是进行长期缓存将变得更加困难,例如,单个更新应用代码将会强制浏览器下载所有 vendor 库,即使它们并没有更新。 如果你想要频繁更新应用的 JavaScript,需要考虑对 vendor 库进行提取和拆分,这样的话,一次修改应用代码不会影响 `vendor.js` 文件的缓存。 `extract` 方法可以接收包含所有库的数组,或你想要提取到 vendor.js 文件的模块: ~~~javascript mix.js('resources/assets/js/app.js', 'public/js') .extract(['vue', 'jquery']); ~~~ 使用上述代码作为示例,Mix将会生成如下文件: * `public/js/manifest.js`:Webpack manifest runtime * `public/js/vendor.js`:vendor 库 * `public/js/app.js`:应用代码 为避免 JavaScript 错误,需要页面确保以正确的顺序加载这些文件: ~~~html ~~~ ### 处理原生 JS `scripts` 方法,可以合并&压缩多个 JavaScript 文件: ~~~javascript mix.scripts([ 'public/js/admin.js', 'public/js/dashboard.js' ], 'public/js/all.js'); ~~~ 这个选项对于不需要为 JavaScript 编写 Webpack 的旧项目非常有用。 >[info] `mix.scripts()` 的一个微小变化是 `mix.babel()`。其方法签名与 `scripts` 一样。不过,连接的文件会经过 Babel 编译,将所有 ES2015 的代码转换为所有浏览器都能识别的原生 JavaScript。 ## 自定义 Webpack 配置 在场景背后,Laravel Mix 引用了预配置的 `webpack.config.js` 文件来尽可能快的启动和运行。 默认应用的配置文件为 `node_modules/laravel-mix/setup/webpack.config.js`。 使用 `webpackConfig` 方法可以覆盖默认的 Webpack 配置。方法接收一个对象,该对象包含了任意你想要应用的 [Webpack 指定配置](https://webpack.js.org/configuration/)。 ## 代码压缩 ### CSS 代码压缩 使用 [`optimize-css-assets-webpack-plugin`](http://npm.taobao.org/package/optimize-css-assets-webpack-plugin) 来压缩 CSS: ~~~javascript mix.webpackConfig({ plugins: [ new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true, discardComments: { removeAll: true } } }) ] }); ~~~ ### JS 代码压缩 `options` 方法,传入任何需要的 [UglifyJsPlugin](https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin) 配置选项,JS 代码将在生产模式下自动被压缩。 默认配置如下: ~~~javascript mix.options({ uglify: { uglifyOptions: { sourceMap: false, // 关闭资源映射 compress: { warnings: false, drop_console: true // 去除控制台输出代码 }, output: { comments: false // 去除所有注释 } } } }); ~~~ 选项解析: 属性 | 类型 | 默认值 | 描述 | --- | --- | --- | --- | compress | boolean, object | true | [见 UglifyJS 文档](https://github.com/mishoo/UglifyJS2#compress-options)。 mangle | boolean, object | true | [见 UglifyJS 文档](https://github.com/mishoo/UglifyJS2#compress-options)。 beautify | boolean | false | 美化输出。 output | 一个提供 UglifyJS OutputStream 选项的对象 | | 更底层地访问 UglifyJS 输出。 comments | boolean, RegExp, function(astNode, comment) -> boolean | 默认保存包含 `/*!`, `/**!`, `@preserve` or `@license` 的注释 | 注释相关的配置。 sourceMap | boolean | false | 使用 SourceMaps 将错误信息的位置映射到模块。这会减慢编译的速度。 test | RegExp, Array | `/.js($|\?)/i` | 测试匹配的文件。 include | RegExp, Array | | 只测试包含的文件。 exclude | RegExp, Array | | 要从测试中排除的文件。 ## 拷贝文件和目录 `copy` 方法拷贝文件和目录到新路径,这在将 `node_modules` 目录下的特定资源文件重新放置到 `public` 目录下时很有用: ~~~javascript mix.copy('node_modules/foo/bar.css', 'public/css/bar.css'); ~~~ 复制目录时,`copy` 方法会平面化目录的结构。要维护目录的原始结构,应该使用 `copyDirectory` 方法: ~~~javascript mix.copyDirectory('assets/img', 'public/img'); ~~~ ## 版本号和缓存刷新 `version` 方法为编译的前端资源添加时间戳或唯一令牌后缀,可以强制浏览器加载最新版本而不是代码的缓存副本。 该方法会自动附加唯一 hash 值到已编译文件名,从而方便实现缓存刷新: ~~~javascript mix.js('resources/assets/js/app.js', 'public/js') .version(); ~~~ 生成版本文件后,还不知提取的文件名,所以需要在 视图 中使用 Laravel 全局的 `mix` 函数来加载相应的带 hash 值的前端资源。`mix` 函数会自动判当前的 hash 文件名: ~~~html ~~~ 由于版本文件在本地开发中没有什么用,可以使用 `inProduction` 方法,只在生产模式下进行版本处理操作: ~~~javascript mix.js('resources/assets/js/app.js', 'public/js'); if (mix.inProduction()) { mix.version(); } ~~~ ## 修改后 `webpack.mix.js` 文件示例 ~~~javascript let mix = require('laravel-mix'); const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); /* |-------------------------------------------------------------------------- | Mix Asset Management |-------------------------------------------------------------------------- | | Mix provides a clean, fluent API for defining some Webpack build steps | for your Laravel application. By default, we are compiling the Sass | file for the application as well as bundling up all the JS files. | */ mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css'); if (mix.inProduction()) { // 生产模式下的特殊配置 mix.webpackConfig({ plugins: [ // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true, discardComments: { removeAll: true } } }) ] }).version(); } ~~~
';

第二节 Laravel Mix 前端资源编译

最后更新于:2022-04-02 01:42:01

本节涉及以下目录或文件: > * node_modules/ > * public/ > * resources/assets/ > * package.json > * webpack.mix.js 大致流程为: 1. [配置 webpack.mix.js 指定 Mix 任务](frontend/mix/configuration.md) 2. [修改 resources/assets 前端资源文件](frontend/mix/modify.md) 3. [运行 Mix 任务编译和监控代码](frontend/mix/run.md)
';

第一节 Yarn 安装前端扩展包

最后更新于:2022-04-02 01:41:58

本节涉及以下目录或文件: > * node_modules/ > * resources/assets/ > * package.json Laravel 前端默认 ui 是 [Bootstrap](https://github.com/twbs/bootstrap),本教程将其替换为 [Semantic UI](http://www.semantic-ui.com/)。 [TOC] ## 修改 `package.json` 文件 `package.json` 文件位于项目根目录下。 ### 默认版 ~~~json { "private": true, "scripts": { "dev": "npm run development", "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "watch-poll": "npm run watch -- --watch-poll", "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { "axios": "^0.16.2", "bootstrap-sass": "^3.3.7", "cross-env": "^5.0.1", "jquery": "^3.1.1", "laravel-mix": "^1.0", "lodash": "^4.17.4", "vue": "^2.1.10" } } ~~~ >[info] 默认集成的 NPM 扩展包: > 1. bootstrap-sass —— Bootstrap NPM 扩展包; > 2. jquery —— jQuery NPM 扩展包; > 3. laravel-mix —— 由 Laravel 官方提供的静态资源管理工具; > 4. vue —— VUE.js 前端框架; ### 修改后 ~~~json { "private": true, "scripts": { "dev": "npm run development", "development": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "watch-poll": "npm run watch -- --watch-poll", "hot": "NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { "axios": "^0.16.2", "cross-env": "^5.0.1", "jquery": "^3.1.1", "laravel-mix": "^1.0", "lodash": "^4.17.4", "nprogress": "^0.2.0", "optimize-css-assets-webpack-plugin": "^3.2.0" } } ~~~ >[danger] 修改概要: > 1. 暂时去除 `vue`,加入 `nprogress`。 > 2. 添加 `optimize-css-assets-webpack-plugin` 用来压缩 CSS。 > 3. 修改去掉 `scripts` 字段中的全部 `cross-env`。因为虚拟机为 Linux 环境,不需要 `cross-env`,否则会各种报错。 ## 使用 `Yarn` 安装扩展包 在项目根目录下运行 ~~~bash $ yarn install --no-bin-links ~~~ 成功后显示: ~~~bash yarn install v0.27.5 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... success Saved lockfile. Done in 153.67s. ~~~ ### Yarn & NPM 常用命令 |NPM | Yarn | 释义 | |---|---|---| | `npm install` | `yarn` | 安装当前项目的所有包 | | `npm install taco --save` | `yarn add taco` | taco 包被添加到 package.json 的 "dependencies" 中 | | `npm uninstall taco --save` | `yarn remove taco` | 从项目中移除 taco 包 | | `npm install taco --save-dev` | `yarn add taco --dev` | taco 包被添加到 package.json 的 "devDependencies" 中 | | `npm update --save` | `yarn upgrade` | 更新包 | >[info] 运行时需要用到的包使用 `--save`,否则使用 `--save-dev`。 > 不挂 VPN 或某些报错的情况下,可用 `cnpm` 代替 `npm`。 >[danger] 注意事项: > 在 Windows 下的 Homestead 虚拟机中,运行 npm 或 yarn 添加移除或更新包时,命令需带 `--no-bin-links`。 > 如果某次执行没有带上,很可能造成包丢失或者其他错误。 ### 如遇报错可尝试 1. `Ctrl+C` 停止 2. 清空旧的安装包 * 主机中全局安装 `rimraf`(仅首次) ~~~bash > npm install -g rimraf ~~~ * 主机中使用 `rimraf` 删除 `node_modules` 文件夹 ~~~bash > cd E:/Homestead/code/Laravel > rimraf node_modules ~~~ * 虚拟机中执行 ~~~bash $ npm cache clear --force ~~~ 3. 重新执行安装命令 ~~~bash $ yarn install --no-bin-links ~~~ ## 添加 `semantic-ui` 依赖 ~~~bash $ yarn add semantic-ui --dev --no-bin-links ~~~ 安装进行至此,会卡在 `Starting 'run setup'` 这步: ~~~bash yarn add v0.27.5 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... [1/1] ⠐ semantic-ui: Starting 'run setup'... [-/1] ⠈ waiting... [-/1] ⠈ waiting... [-/1] ⠈ waiting... [-/1] ⠈ waiting... ~~~ >[warning] 这也是为什么不直接将 `semantic-ui` 依赖写入 `package.josn` 的原因,避免卡住无限制 `waiting`。 `Ctrl+C` 强制退出,手动执行安装: ~~~bash $ cd node_modules/semantic-ui/ $ gulp install ~~~ 安装选项概要: >[info] 1. 通过上下箭头选择,回车选定。 > 2. 将Semantic UI资源文件安装到 `resources/assets/semantic` 文件夹中。 ~~~bash Starting 'run setup'... ? Set-up Semantic UI (Use arrow keys) Automatic (Use default locations and all components) ❯ Express (Set components and output folder) Custom (Customize all src/dist values) ? We detected you are using NPM Nice! Is this your project folder? /home/vagrant/Code/Laravel ❯ Yes No, let me specify // 这里设置资源输出目标文件夹 ? Where should we put Semantic UI inside your project? (semantic/) resources/assets/semantic/ ? What components should we include in the package? (Press to select, to toggle all, to inverse selection) ❯◉ reset ◉ site ◉ button ◉ container ◉ divider ◉ flag ◉ header (Move up and down to reveal more choices) ? Should we set permissions on outputted files? No ? Do you use a RTL (Right-To-Left) language? No ? Where should we output Semantic UI? dist · · Installing ------------------------------ Installing to resources/assets/semantic/ · · Setup Complete! Installing Peer Dependencies. Please refrain from ctrl + c... After completion navigate to resources/assets/semantic/ and run "gulp build" to build ~~~ 安装完毕后执行以下命令,生成 Semantic UI 的 js 和 css 文件: ~~~bash $ cd ~/Code/Laravel/resources/assets/semantic/ $ gulp build ~~~ 生成完毕后,记得返回项目根目录。 最终,`package.json` 文件中不会添加 `semantic-ui` 依赖,但 `yarn.lock` 文件中已经有相关记录。 如果再次执行最初的添加`semantic-ui` 依赖的命令,则会跳过安装过程直接添加依赖到`package.json` 文件中,提示: ~~~bash yarn add v0.27.5 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... success Saved 1 new dependency. └─ semantic-ui@2.2.13 Done in 80.53s. ~~~
';

第二章 前端工作流

最后更新于:2022-04-02 01:41:56

Laravel 利用 NPM, Yarn, Laravel Mix 构成了一套完整的前端工作流。 [TOC] ## Yarn 可以使用 [NPM](https://github.com/npm/npm) 对前端扩展包进行安装,但由于 NPM 的安装速度、安全性和稳定性等都饱受开发者的诟病,因此改用 Facebook 在 2016 年的 10 月份开源的 [Yarn](https://github.com/yarnpkg/yarn) 来作为 NPM 的替代品。 本教程提供的定制化 Homestead 安装包中,已默认集成了 Yarn,因此不必再重复安装 Yarn。如果想知道 Yarn 具体的安装方式,可查阅 [Yarn 官方安装文档](https://yarnpkg.com/en/docs/install)。 ## Laravel Mix [Laravel Mix](https://github.com/JeffreyWay/laravel-mix) 一款前端任务自动化管理工具,使用了工作流的模式对制定好的任务依次执行。Mix 提供了简洁流畅的 API,来为 Laravel 应用定义 Webpack 编译任务。 Mix 支持许多常见的 CSS 与 JavaScript 预处理器,通过简单的调用,可以轻松地管理前端资源。此外还可以在 webpack.mix.js 文件中制定一些,如资源文件的编译、压缩等任务。 Laravel 已默认生成了 `webpack.mix.js` 文件,并集成了 laravel-mix 模块。可以通过简单的方法链,流式定义资源管道。例如: ~~~javascript mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css'); ~~~ ## SASS Sass 是一种可用于编写 CSS 的语言,起初由 Hampton Catlin 进行设计并由 Natalie Weizenbaum 开发。借助 Sass 可以少写很多 CSS 代码,并使样式代码的编写更加灵活多变。
';

总结 本章命令概览

最后更新于:2022-04-02 01:41:54

[TOC] ## 日常命令 ### 启动 Homestead 并登录 ~~~bash > cd E:/Homestead && vagrant up && vagrant ssh $ cd ~/Code/Laravel ~~~ ### 退出与关闭虚拟机 ~~~bash $ exit > vagrant halt ~~~ ### 日常更新至线上 ~~~bash $ git add -A $ git commit -m "更新" $ git push ~~~ #### 强制撤销暂存区更改 ~~~bash $ git checkout -f ~~~ #### 建立分支 ~~~bash $ git checkout master $ git checkout -b filling-layout-style ~~~ ## 初始配置命令 ### 添加虚拟盒子 ~~~bash > cd E:/lt-homestead-3-0-0-2017082400 > vagrant box add metadata.json ~~~ ### 下载管理脚本并初始化 ~~~bash > cd E:/ > git clone https://git.coding.net/summerblue/homestead.git Homestead > cd Homestead > bash init.sh ~~~ ### 打开文件管理器 ~~~bash > explorer . ~~~ ### 编辑 Homestead.yaml 配置文件 样本如下 ~~~ --- ip: "192.168.10.10" memory: 2048 cpus: 1 provider: virtualbox authorize: ~/.ssh/id_rsa.pub keys: - ~/.ssh/id_rsa - ~/.ssh/id_rsa.pub folders: - map: E:/Homestead/code to: /home/vagrant/Code sites: - map: homestead.app to: /home/vagrant/Code/Laravel/public databases: - homestead # blackfire: # - id: foo # token: bar # client-id: foo # client-token: bar # ports: # - send: 50000 # to: 5000 # - send: 7777 # to: 777 # protocol: udp ~~~ ### SSH key 检测与生成 ~~~bash > ls -al ~/.ssh > ssh-keygen -t rsa -C "your_email@example.com" ~~~ ### 生成代码摆放文件夹 ~~~bash > cd E:/Homestead > mkdir code ~~~ ### 修改 hosts 文件位于`C:\Windows\System32\Drivers\etc\hosts` ~~~text 192.168.10.10 homestead.app ~~~ ### 启动 Homestead 并登录 ~~~bash > cd E:/Homestead && vagrant up > vagrant ssh ~~~ ### 创建 Laravel 应用 ~~~bash $ cd ~/Code $ composer create-project laravel/laravel Laravel --prefer-dist "5.5.*" ~~~ ### 第一次运行虚拟机,进行 Git 配置 ~~~bash $ git config --global user.name "Your Name" $ git config --global user.email your_email@example.com $ git config --global push.default simple ~~~ ### 初始化一个本地 Git 项目 ~~~bash $ cd ~/Code/Laravel $ git init ~~~ ### 项目文件保存到暂存区 ~~~bash $ git add -A ~~~ ### 暂存区文件列表 ~~~bash $ git status ~~~ ### 提交到 Git ~~~bash $ git commit -m "Initial commit" ~~~ ### 线上代码仓库配置 #### 将 `SSH Key` 添加到 `ssh-agent` 中 ~~~bash $ eval `ssh-agent -s` $ ssh-add ~/.ssh/id_rsa ~~~ #### 打印并复制,再黏贴到线上 SSH 令牌管理页面 ~~~bash > cat ~/.ssh/id_rsa.pub ~~~ #### 将代码上传到 Gitee 上完成托管 ~~~bash $ git remote add origin git@gitee.com:your_name/laravel.git $ git push -u origin master ~~~
';

第七节 使用 Git 进行版本控制

最后更新于:2022-04-02 01:41:52

在现代化的项目开发中,Git 基本上是标配。 [TOC] ## Git 的基本设置 在[前面的章节](environment/install-git.md)中已经为主机安装好了 Git,虚拟机 Homestead 中 Git 也是作为默认安装的软件。 接下来大部分的 Git 操作都会发生在 Homestead 虚拟机中,首先需要对其进行设置。 ### 个人信息配置 首先对 Git 进行用户名和邮箱进行设置,此设置的作用是,在代码提交时自动署名标记,方便查看提交日志时区分作者。 参照下面格式,替换为自己常用的用户名和邮箱: ~~~bash $ git config --global user.name "Your Name" $ git config --global user.email your_email@example.com ~~~ > `--global` 选项代表对 Git 进行全局设置。 ### 推送分支时相关配置 此设置是 Git 命令 push 的默认模式为 `simple`,当我们执行 `git push` 没有指定分支时,自动使用当前分支,而不是报错。 ~~~bash $ git config --global push.default simple ~~~ ## 将项目纳入到 Git 代码版本管理 ### 对 Git 进行初始化 ~~~bash $ cd ~/Code/Laravel $ git init ~~~ ### 将项目所有文件纳入到 Git 中 ~~~bash $ git add -A ~~~ >[info] `.gitignore` 文件中设置的除外 ### 检查 Git 状态 ~~~bash $ git status ~~~ >[warning] 输出存放在 Git 暂存区的文件,这些文件还未真正提交到 Git 中。 ### 保留改动并提交 将暂存区的文件都提交到 Git ~~~bash $ git commit -m "Initial commit" ~~~ >[info] `-m` 选项后面的参数,表示本次提交的简单描述。 ### 查看历史提交记录 ~~~bash $ git log ~~~ >[info] 按 `q` 可退出查看 ## 线上仓库配置 ### 为 Gitee 账号设置 `SSH Key` 1. 将 `SSH Key` 添加到 `ssh-agent` 中: ~~~bash $ eval `ssh-agent -s` $ ssh-add ~/.ssh/id_rsa ~~~ 2. 回到 **主机中** 打印出公钥 `id_rsa.pub` 文件里的内容: ~~~bash > cat ~/.ssh/id_rsa.pub ~~~ 3. 把输出的内容复制到剪贴板里,黏贴到线上 SSH 令牌[管理页面](https://gitee.com/profile/sshkeys) ### 线上创建项目仓库 `laravel` ### 虚拟机中执行以下命令,将代码上传到 Gitee 上完成托管 ~~~bash $ git remote add origin git@gitee.com:your_name/laravel.git $ git push -u origin master ~~~ ### 日常代码更新推送 #### 保存到暂存区 ~~~bash $ git add -A ~~~ #### 提交到本地 Git ~~~bash $ git commit -m "Say something" ~~~ >[info] `-m` 选项后面的参数,表示本次提交的简单描述。 #### 撤销文件更改 如需将在暂存区的更改文件进行强制撤销,可执行 ~~~bash $ git checkout -f ~~~ #### 将代码推送到线上 ~~~bash $ git push ~~~
';

第六节 创建 Laravel 应用

最后更新于:2022-04-02 01:41:49

[TOC] ## 创建 Laravel 应用 ### 开启并登录 Homestead 虚拟机 ~~~bash > cd E:/Homestead && vagrant up > vagrant ssh ~~~ ### 新建一个名为 Laravel 的项目 ~~~bash $ cd ~/Code $ composer create-project laravel/laravel Laravel --prefer-dist "5.5.*" ~~~ 完成之后,访问 http://homestead.app 可以看到 Laravel 为我们生成默认界面。 ## Laravel 文件夹结构 | 文件夹名称 | 简介 | | --------------------- | --------------------------------------- | | app | 应用程序的业务逻辑代码存放文件夹 | | app/Console | 存放自定义 Artisian 命令文件 | | app/Http/Controllers | 存放控制器文件 | | app/Http/Middleware | 存放「中间件」文件| | bootstrap | 框架启动与自动加载设置相关的文件| | composer.json | 应用依赖的扩展包| | composer.lock | 扩展包列表,确保这个应用的副本使用相同版本的扩展包| | config | 应用程序的配置文件| | database | 数据库操作相关文件(数据库迁移和数据填充)| | node_modules | 存放 NPM 依赖模块| | package.json | 应用所需的 NPM 包配置文件| | phpunit.xml | 测试工具 PHPUnit 的配置文件| | public | 前端控制器和资源相关文件(图片、JavaScript、CSS)| | readme.md | 项目介绍说明文件| | resources | 应用资源| | resources/assets | 未编译前的应用资源文件(图片、JavaScript、CSS)| | resources/lang | 多语言文件| | resources/views | 视图文件| | routes/api.php | 用于定义 API 类型的路由| | routes/channels.php | 事件转播注册信息| | routes/console.php | 用于定义 Artisan 命令| | routes/web.php | 用于定义 Web 类型的路由(重点,大部分情况下本书会用到)| | server.php | 使用 PHP 内置服务器时的 URL 重写(类似于 Apache 的 "mod_rewrite" )| | storage | 编译后的视图、基于会话、文件缓存和其它框架生成的文件| | storage/app | 目录可用于存储应用程序使用的任何文件| | storage/framework | 目录被用于保存框架生成的文件及缓存| | storage/logs | 应用程序的日志文件| | tests | 应用测试相关文件| | vendor | Composer 依赖模块| | webpack.mix.js | Laravel 的前端工作流配置文件| | yarn.lock | Yarn 依赖版本锁定文件| | .gitignore | 被 Git 所忽略的文件| | .env | 环境变量配置文件|
';