<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Laravel 新項目避坑指南10 大基礎(chǔ)設(shè)置讓代碼半年不崩

      Laravel 新項目避坑指南10 大基礎(chǔ)設(shè)置讓代碼半年不崩

      有沒有遇到過這種 Laravel 項目:剛上線那會兒干干凈凈,過三個月就變成無法收拾的災(zāi)難?Controller 動不動就 500 多行、慢得要命的數(shù)據(jù)庫查詢隨處可見,甚至有人把 .env 推上 GitHub,所有密鑰一夜之間全線暴露。

      別以為只有你栽過這種坑。來自開發(fā)者論壇和 Stack Overflow 的統(tǒng)計顯示:Laravel 應(yīng)用里的性能問題有 70% 可以在一開始就避免,接近 50% 的安全事故也都是初始配置不到位造成的。

      原文鏈接 Laravel 新項目避坑指南:10 大基礎(chǔ)設(shè)置讓代碼半年不崩

      別只會復(fù)制 .env——先搞懂它!

      常見問題

      很多新手只會把 .env.example 復(fù)制成 .env,填上數(shù)據(jù)庫賬號就直接 php artisan serve。問題是,這個文件里藏著許多直接影響線上環(huán)境的配置,稍不留神就會出事。

      真實案例:有開發(fā)者上線后忘了把 APP_DEBUG=true 改成 false,結(jié)果所有錯誤信息包括 SQL 查詢、文件路徑、敏感數(shù)據(jù)全都暴露,黑客看到簡直像打開盲盒。

      正確做法

      # 線上環(huán)境一定要設(shè)成 false!
      APP_DEBUG=false
      APP_ENV=production
      
      # 生成獨一無二的 key,別用默認(rèn)值
      APP_KEY=base64:xxxxx
      
      # 線上別寫 127.0.0.1
      APP_URL=https://yourdomain.com
      
      # 數(shù)據(jù)庫憑據(jù)千萬別提交到 Git!
      DB_CONNECTION=mysql
      DB_HOST=127.0.0.1
      DB_PORT=3306
      DB_DATABASE=your_database_name
      DB_USERNAME=database_user
      DB_PASSWORD=strong_password_please
      
      # 會話與緩存驅(qū)動
      SESSION_DRIVER=redis
      CACHE_DRIVER=redis
      QUEUE_CONNECTION=redis
      

      實用提醒

      • 生成強隨機 APP_KEY:每個新項目都要跑一遍 php artisan key:generate,它可是用來加密 Session 等敏感數(shù)據(jù)的。
      • 維護完整的 .env.example:把所有必須的變量都列出來,但不要寫真實值,方便團隊協(xié)作。
      • 確認(rèn) .env 沒進 Git:默認(rèn) .gitignore 會忽略它,但還是要確認(rèn)。如果不小心提交了,趕緊這么做:
      git rm --cached .env
      git commit -m "Remove .env from version control"
      

      從第一天就定下命名規(guī)范

      常見問題

      // 糊里糊涂的 Controller
      class Users extends Controller {
          public function GetUserData() {
              $All_Users = User::all();
              return view('user-list', ['data' => $All_Users]);
          }
      }
      
      // 奇怪的 migration
      Schema::create('User', function (Blueprint $table) {
          $table->id();
          $table->string('UserName');
          $table->string('user-email');
      });
      

      如果有新人接手這種代碼,第一反應(yīng)肯定是“這是邊吃飯邊寫的吧?”。

      正確做法

      Laravel 社區(qū)已經(jīng)約定俗成了一套命名規(guī)范,照著走就省事。

      模型

      // ? 使用單數(shù)、PascalCase
      class Article extends Model {
          // hasMany 關(guān)系 → 復(fù)數(shù)
          public function comments() {
              return $this->hasMany(Comment::class);
          }
          
          // belongsTo 關(guān)系 → 單數(shù)
          public function author() {
              return $this->belongsTo(User::class);
          }
      }
      
      // ? 錯誤示范
      class Articles extends Model { }
      class article extends Model { }
      

      控制器

      // ? 單數(shù)、PascalCase,并以 Controller 結(jié)尾
      class ArticleController extends Controller {
          // 方法用 camelCase
          public function showLatest() {
              // 變量也用 camelCase
              $latestArticles = Article::latest()
                  ->take(5)
                  ->get();
                  
              return view('articles.latest', [
                  'articles' => $latestArticles
              ]);
          }
      }
      
      // ? 錯誤示范
      class ArticlesController { }  // 復(fù)數(shù)
      class articleController { }   // 小寫開頭
      class Article_Controller { }  // 下劃線
      

      遷移和數(shù)據(jù)庫

      // ? 復(fù)數(shù)、snake_case
      Schema::create('blog_posts', function (Blueprint $table) {
          $table->id();
          $table->string('post_title');
          $table->text('post_content');
          $table->foreignId('category_id')
                ->constrained('categories')
                ->onDelete('cascade');
          $table->timestamps();
      });
      
      // ? 單數(shù)或 PascalCase
      Schema::create('BlogPost', function (Blueprint $table) {
          $table->string('PostTitle');
      });
      

      路由

      // ? 復(fù)數(shù)、kebab-case
      Route::get('/blog-posts', [BlogPostController::class, 'index'])
          ->name('blog-posts.index');
      
      // ? 錯誤示范
      Route::get('/BlogPosts', [BlogPostController::class, 'index']);
      Route::get('/blog_posts', [BlogPostController::class, 'index']);
      

      為什么要這么做?

      想象你和 5 個開發(fā)一起合作,每個人有一套命名習(xí)慣,整個代碼庫就像水果撈一樣亂七八糟。統(tǒng)一命名帶來的好處:

      • 新人上手快,不用猜。
      • 排查 Bug 更輕松,一眼就知道誰是模型誰是控制器。
      • IDE 自動補全更精準(zhǔn),PHPStorm、VS Code 都會更懂你。

      外鍵約束必須上,別全靠代碼兜底!

      常見問題

      // ? 敷衍的建表
      Schema::create('posts', function (Blueprint $table) {
          $table->id();
          $table->unsignedBigInteger('user_id'); // 只是普通字段
          $table->string('title');
          $table->timestamps();
      });
      

      看起來沒毛病?等等,這里有三個隱患:

      • 孤兒數(shù)據(jù):用戶刪了,帖子還在,$post->user 直接報錯 Trying to get property of null。
      • 數(shù)據(jù)不一致:別人可以插入不存在的 user_id,數(shù)據(jù)庫全是垃圾數(shù)據(jù)。
      • 調(diào)試噩夢:出問題時只能一個一個查數(shù)據(jù)。

      有人說“我們可以靠 Laravel Observer 或 Events 處理邏輯”。確實,但這不是 100% 保險:

      • 原生 SQL 會繞過 Eloquent。
      • 批量導(dǎo)入直接寫數(shù)據(jù)庫。
      • 任何一個忘記觸發(fā)事件的 Bug。

      數(shù)據(jù)照樣會爛掉。

      正確做法

      // ? 建表時加外鍵約束
      Schema::create('posts', function (Blueprint $table) {
          $table->id();
          $table->foreignId('user_id')
                ->constrained('users')
                ->onDelete('cascade');  // 也可以是 restrict、set null 等
          $table->string('title');
          $table->text('content');
          $table->timestamps();
      });
      
      // 更復(fù)雜的關(guān)系
      Schema::create('comments', function (Blueprint $table) {
          $table->id();
          $table->foreignId('post_id')
                ->constrained()  // 自動推斷 posts 表
                ->onDelete('cascade');
          $table->foreignId('user_id')
                ->constrained()
                ->onDelete('restrict');  // 有評論的用戶禁止刪除
          $table->text('comment_body');
          $table->timestamps();
      });
      

      你需要理解的選項

      // 1. CASCADE - 刪除父記錄時一起刪
      ->onDelete('cascade')
      
      // 2. RESTRICT - 阻止刪除父記錄
      ->onDelete('restrict')
      
      // 3. SET NULL - 設(shè)置為 NULL(記得列要 nullable)
      ->onDelete('set null')
      ->nullable()
      
      // 4. NO ACTION - MySQL 默認(rèn)行為
      ->onDelete('no action')
      

      什么時候可以不加?

      • 分片數(shù)據(jù)庫:比如 PlanetScale 不支持外鍵。
      • 一人維護的小項目:你能保證數(shù)據(jù)一致性。
      • 極端性能場景:外鍵會增加一點點開銷(其實很少見)。

      對 99% 的項目來說,加外鍵一定是最佳選擇。

      起步就躲開 N+1 查詢

      常見問題

      這是 Laravel 性能問題 Top 1。最危險的是,你上線前根本察覺不到。

      // ? 典型的 N+1 查詢
      public function showAllPosts() {
          $posts = Post::all();
          
          return view('posts.index', compact('posts'));
      }
      
      {{-- Blade 視圖 --}}
      @foreach($posts as $post)
          <div class="post">
              <h2>{{ $post->title }}</h2>
              <p>By: {{ $post->user->name }}</p>  <!-- 危險! -->
              <p>{{ $post->comments->count() }} comments</p>  <!-- 也危險! -->
          </div>
      @endforeach
      

      如果有 100 篇帖子?

      • 1 次取 posts。
      • 100 次取用戶。
      • 100 次統(tǒng)計 comments。

      總共 201 條查詢,服務(wù)器直接崩潰。

      正確做法

      // ? 預(yù)加載
      public function showAllPosts() {
          $posts = Post::with(['user', 'comments'])
              ->latest()
              ->get();
          
          return view('posts.index', compact('posts'));
      }
      
      // ? 只需要數(shù)量時用 withCount
      public function showAllPosts() {
          $posts = Post::with('user')
              ->withCount('comments')
              ->latest()
              ->get();
          
          return view('posts.index', compact('posts'));
      }
      

      只需要 3 條查詢,性能翻倍都不止。

      從第一天就裝 Laravel Debugbar

      在開發(fā)環(huán)境安裝它:

      composer require barryvdh/laravel-debugbar --dev
      

      Debugbar 會實時顯示:

      • 當(dāng)前頁面跑了多少條查詢。
      • 每條查詢耗時。
      • 是否有重復(fù)查詢。

      黃金法則:單頁查詢超過 20 條就要警覺。

      小技巧:Lazy Eager Loading

      // 即使你已經(jīng)拿到了 $posts
      $posts = Post::all();
      
      // 仍然可以臨時加載關(guān)聯(lián)
      $posts->load(['user', 'comments']);
      

      建 Service 層,別把所有邏輯塞進 Controller!

      常見問題

      // ? 典型的胖 Controller
      class OrderController extends Controller 
      {
          public function checkout(Request $request) 
          {
              $validated = $request->validate([
                  'items' => 'required|array',
                  'payment_method' => 'required|string',
                  'shipping_address' => 'required|string'
              ]);
              
              DB::beginTransaction();
              try {
                  // 50 行計算邏輯
                  $total = 0;
                  foreach ($validated['items'] as $item) {
                      $product = Product::find($item['id']);
                      $total += $product->price * $item['quantity'];
                      $product->stock -= $item['quantity'];
                      $product->save();
                  }
                  
                  // 30 行支付邏輯
                  if ($validated['payment_method'] === 'credit_card') {
                      // 處理信用卡
                  } elseif ($validated['payment_method'] === 'bank_transfer') {
                      // 處理銀行轉(zhuǎn)賬
                  }
                  
                  // 40 行物流邏輯
                  $shippingCost = $this->calculateShipping(...);
                  
                  // 20 行創(chuàng)建訂單邏輯
                  $order = Order::create([...]);
                  
                  // 15 行發(fā)郵件邏輯
                  Mail::to($user)->send(new OrderConfirmation($order));
                  
                  // 10 行發(fā)通知邏輯
                  
                  DB::commit();
                  return redirect()->route('orders.success');
              } catch (\Exception $e) {
                  DB::rollback();
                  return back()->withErrors('Order failed');
              }
          }
      }
      

      這種 Controller 動輒 150+ 行,維護成本爆炸,邏輯也沒法復(fù)用。

      正確做法:拆到 Service 層

      // ? 精簡后的 Controller
      class OrderController extends Controller 
      {
          public function __construct(
              private OrderService $orderService
          ) {}
          
          public function checkout(CheckoutRequest $request) 
          {
              try {
                  $order = $this->orderService->processCheckout(
                      $request->validated()
                  );
                  
                  return redirect()
                      ->route('orders.success', $order->id)
                      ->with('success', '訂單處理成功!');
                      
              } catch (InsufficientStockException $e) {
                  return back()->withErrors('商品庫存不足');
              } catch (PaymentFailedException $e) {
                  return back()->withErrors('支付失敗');
              }
          }
      }
      

      看到了嗎?Controller 只做它該做的:接請求、調(diào)用服務(wù)、給出響應(yīng)。

      // app/Services/OrderService.php
      class OrderService 
      {
          public function __construct(
              private CartService $cartService,
              private PaymentService $paymentService,
              private ShippingService $shippingService,
              private NotificationService $notificationService
          ) {}
          
          public function processCheckout(array $data): Order 
          {
              return DB::transaction(function () use ($data) {
                  // 校驗庫存
                  $this->cartService->validateStock($data['items']);
                  
                  // 計算總價
                  $orderTotal = $this->cartService->calculateTotal($data['items']);
                  
                  // 計算運費
                  $shippingCost = $this->shippingService->calculate(
                      $data['shipping_address']
                  );
                  
                  // 處理支付
                  $payment = $this->paymentService->charge(
                      $data['payment_method'],
                      $orderTotal + $shippingCost
                  );
                  
                  // 創(chuàng)建訂單
                  $order = $this->createOrder($data, $payment);
                  
                  // 減庫存
                  $this->cartService->reduceStock($data['items']);
                  
                  // 發(fā)通知
                  $this->notificationService->sendOrderConfirmation($order);
                  
                  return $order;
              });
          }
          
          private function createOrder(array $data, Payment $payment): Order 
          {
              // 專注處理創(chuàng)建訂單的細(xì)節(jié)
              return Order::create([
                  'user_id' => auth()->id(),
                  'payment_id' => $payment->id,
                  'total_amount' => $payment->amount,
                  'status' => OrderStatus::PENDING,
                  // ... 其他字段
              ]);
          }
      }
      

      推薦目錄結(jié)構(gòu)

      app/
      ├── Http/
      │   ├── Controllers/
      │   │   └── OrderController.php
      │   └── Requests/
      │       └── CheckoutRequest.php
      ├── Services/
      │   ├── OrderService.php
      │   ├── CartService.php
      │   ├── PaymentService.php
      │   └── ShippingService.php
      ├── Models/
      │   ├── Order.php
      │   ├── Product.php
      │   └── Payment.php
      └── Exceptions/
          ├── InsufficientStockException.php
          └── PaymentFailedException.php
      

      好處一籮筐

      • 可測試性:每個 Service 都能單獨寫測試。
      • 可復(fù)用:邏輯可以給 API、命令、隊列復(fù)用。
      • 可維護:Bug 和新需求都能快速定位。
      • 團隊協(xié)作:大家分模塊開發(fā),沖突更少。

      請求驗證交給 Form Request,別堆在 Controller!

      常見問題

      // ? Controller 里塞滿驗證
      public function store(Request $request) 
      {
          $validated = $request->validate([
              'title' => 'required|max:255|unique:posts',
              'slug' => 'required|unique:posts',
              'content' => 'required|min:100',
              'category_id' => 'required|exists:categories,id',
              'tags' => 'required|array',
              'tags.*' => 'exists:tags,id',
              'featured_image' => 'required|image|max:2048',
              'meta_title' => 'required|max:60',
              'meta_description' => 'required|max:160',
              // ... 還有一堆
          ]);
          
          // 后面才是創(chuàng)建邏輯
      }
      

      問題在于:

      • Controller 變得臃腫。
      • 驗證規(guī)則無法復(fù)用。
      • 自定義提示語很難管理。
      • 復(fù)雜邏輯不好寫。

      正確做法:使用 Form Request

      php artisan make:request StorePostRequest
      
      // app/Http/Requests/StorePostRequest.php
      class StorePostRequest extends FormRequest
      {
          public function authorize(): bool
          {
              // 判斷當(dāng)前用戶是否能創(chuàng)建文章
              return auth()->user()->can('create-post');
          }
      
          public function rules(): array
          {
              return [            
                  'title' => ['required', 'max:255', 'unique:posts,title'],
                  'slug' => ['required', 'unique:posts,slug', 'regex:/^[a-z0-9-]+$/'],
                  'content' => 'required|min:100',
                  'category_id' => 'required|exists:categories,id',
                  'tags' => 'required|array|min:1|max:5',
                  'tags.*' => 'exists:tags,id',
                  'featured_image' => 'required|image|mimes:jpg,png,webp|max:2048',
                  'meta_title' => 'nullable|max:60',
                  'meta_description' => 'nullable|max:160',
                  'publish_at' => 'nullable|date|after:now',
              ];
          }
          
          public function messages(): array
          {
              return [
                  'title.required' => '文章標(biāo)題是必填項!',
                  'title.unique' => '標(biāo)題已存在,換個更有創(chuàng)意的吧!',
                  'slug.regex' => 'Slug 只能包含小寫字母、數(shù)字和連字符',
                  'tags.min' => '至少選擇 1 個標(biāo)簽方便分類',
                  'tags.max' => '最多 5 個標(biāo)簽,別太貪心!',
                  'featured_image.max' => '圖片太大了,最大 2MB',
              ];
          }
          
          public function attributes(): array
          {
              return [            
                'category_id' => '分類',            
                'featured_image' => '封面圖',            
                'publish_at' => '發(fā)布時間',        
              ];
          }
          
          // 自定義驗證邏輯
          protected function prepareForValidation(): void
          {
              // 自動根據(jù)標(biāo)題生成 slug
              if (!$this->slug) {
                  $this->merge([
                      'slug' => Str::slug($this->title)
                  ]);
              }
          }
      }
      
      // Controller 變得超級干凈!
      class PostController extends Controller 
      {
          public function store(StorePostRequest $request) 
          {
              // 數(shù)據(jù)自動驗證、自動授權(quán)
              $post = Post::create($request->validated());
              
              // 關(guān)聯(lián)標(biāo)簽
              $post->tags()->attach($request->tags);
              
              return redirect()
                  ->route('posts.show', $post)
                  ->with('success', '文章發(fā)布成功!');
          }
      }
      

      .gitignore 要寫完整

      常見問題

      總有人把不該進倉庫的文件提交進去:

      # ? 常見事故
      .env                  # 數(shù)據(jù)庫密碼全暴露!
      /vendor              # 100MB+ 的依賴
      node_modules/        # 幾千個文件
      .DS_Store           # macOS 垃圾文件
      Thumbs.db           # Windows 垃圾文件
      *.log               # 巨大的日志
      /storage/*.key      # SSL 密鑰
      

      真實事件:有個創(chuàng)業(yè)團隊把 .env 推上了 GitHub,公開倉庫 2 小時內(nèi)服務(wù)器就被人拿去挖礦,AWS 賬單直接漲到 15,000 美元。

      完整的 .gitignore 參考

      # Laravel
      /node_modules
      /public/hot
      /public/storage
      /storage/*.key
      /vendor
      
      # 環(huán)境文件
      .env
      .env.backup
      .env.production
      .env.testing
      .env.*.php
      .phpunit.result.cache
      
      # IDE & 編輯器
      .idea/
      .vscode/
      *.sublime-project
      *.sublime-workspace
      .phpstorm.meta.php
      _ide_helper.php
      _ide_helper_models.php
      
      # 操作系統(tǒng)
      .DS_Store
      .DS_Store?
      ._*
      .Spotlight-V100
      .Trashes
      ehthumbs.db
      Thumbs.db
      desktop.ini
      
      # 日志 & 數(shù)據(jù)庫
      *.log
      *.sql
      *.sqlite
      *.sqlite-journal
      
      # 構(gòu)建產(chǎn)物
      /public/build
      /public/mix-manifest.json
      /public/js/app.js
      /public/css/app.css
      npm-debug.log
      yarn-error.log
      
      # 部署
      .deploy/
      .rocketeer/
      
      # 測試
      /coverage
      /phpunit.xml
      
      # 安全 & 密鑰
      *.pem
      *.key
      .cert
      

      如果 .env 已經(jīng)被提交

      別慌,但動作要快:

      # 1. 從 Git 歷史里移除
      git rm --cached .env
      
      # 2. 提交變更
      git commit -m "Remove .env from version control"
      
      # 3. 推上遠(yuǎn)端
      git push origin main
      
      # 4. 重點!所有泄露的密鑰都要立刻更換
      # - 改數(shù)據(jù)庫密碼
      # - 重生成 API Key
      # - 輪換所有密鑰
      

      如果倉庫是公開的,密鑰在 Git 歷史里就算曝光了,爬蟲早晚會找到。

      制定清晰的日志策略

      常見問題

      不少人靠 dd()、var_dump() 調(diào)試,線上出錯卻沒任何記錄;反過來也有人把所有東西都往日志里塞,結(jié)果 log 文件動輒幾個 G。

      // ? 粗糙的日志
      public function processPayment($orderId) 
      {
          try {
              // 處理支付
              echo "Processing order: " . $orderId;  // 不專業(yè)
              var_dump($paymentData);                // 生產(chǎn)環(huán)境危險
              
              // 支付邏輯
              
          } catch (\Exception $e) {
              // 錯誤直接消失
              return false;
          }
      }
      

      正確做法

      // app/Services/PaymentService.php
      use Illuminate\Support\Facades\Log;
      
      class PaymentService 
      {
          public function processPayment(Order $order): bool 
          {
              Log::info('開始處理支付', [
                  'order_id' => $order->id,
                  'amount' => $order->total,
                  'user_id' => $order->user_id,
                  'timestamp' => now()
              ]);
              
              try {
                  $payment = $this->chargeCustomer($order);
                  
                  Log::info('支付成功', [
                      'order_id' => $order->id,
                      'payment_id' => $payment->id,
                      'gateway' => $payment->gateway
                  ]);
                  
                  return true;
                  
              } catch (PaymentGatewayException $e) {
                  Log::error('支付網(wǎng)關(guān)失敗', [
                      'order_id' => $order->id,
                      'error' => $e->getMessage(),
                      'gateway' => $e->getGateway(),
                      'trace' => $e->getTraceAsString()
                  ]);
                  
                  throw $e;
                  
              } catch (\Exception $e) {
                  Log::critical('支付發(fā)生未知異常', [
                      'order_id' => $order->id,
                      'error' => $e->getMessage(),
                      'file' => $e->getFile(),
                      'line' => $e->getLine()
                  ]);
                  
                  throw $e;
              }
          }
      }
      

      config/logging.php 里配置多通道

      'channels' => [
          'stack' => [
              'driver' => 'stack',
              'channels' => ['daily', 'slack'],
              'ignore_exceptions' => false,
          ],
      
          'daily' => [
              'driver' => 'daily',
              'path' => storage_path('logs/laravel.log'),
              'level' => env('LOG_LEVEL', 'debug'),
              'days' => 14,  // 14 天自動清理
          ],
      
          'payment' => [
              'driver' => 'daily',
              'path' => storage_path('logs/payment.log'),
              'level' => 'info',
              'days' => 90,  // 支付日志保留 3 個月
          ],
      
          'security' => [
              'driver' => 'daily',
              'path' => storage_path('logs/security.log'),
              'level' => 'warning',
              'days' => 365,  // 安全日志留一年
          ],
      
          'slack' => [
              'driver' => 'slack',
              'url' => env('LOG_SLACK_WEBHOOK_URL'),
              'username' => 'Laravel Log',
              'emoji' => ':boom:',
              'level' => 'critical',  // 只有嚴(yán)重問題才打到 Slack
          ],
      ],
      

      別等出 Bug 再想起測試

      常見問題

      “測試?項目跑起來再說吧……”

      這通常意味著:

      • Bug 是線上用戶幫你發(fā)現(xiàn)的。
      • 每次發(fā)版都提心吊膽。
      • 修一個 Bug 引入三個新 Bug。
      • 團隊信心值直接跌到負(fù)數(shù)。

      搭好測試環(huán)境

      # 安裝 Pest(更現(xiàn)代的測試框架)
      composer require pestphp/pest --dev --with-all-dependencies
      php artisan pest:install
      
      # 或者堅持用 PHPUnit
      dcomposer require phpunit/phpunit --dev
      

      .env.testing 示例:

      APP_ENV=testing
      APP_KEY=base64:testing-key-here
      DB_CONNECTION=sqlite
      DB_DATABASE=:memory:
      CACHE_DRIVER=array
      SESSION_DRIVER=array
      QUEUE_CONNECTION=sync
      MAIL_MAILER=array
      

      寫點像樣的測試

      // tests/Feature/OrderTest.php
      <?php
      
      use App\Models\User;
      use App\Models\Product;
      use App\Models\Order;
      
      test('用戶可以在庫存充足時創(chuàng)建訂單', function () {
          // Arrange
          $user = User::factory()->create();
          $product = Product::factory()->create([
              'price' => 100000,
              'stock' => 10
          ]);
          
          // Act
          $response = $this->actingAs($user)
              ->post('/orders', [
                  'product_id' => $product->id,
                  'quantity' => 2
              ]);
          
          // Assert
          $response->assertStatus(201);
          $response->assertJsonStructure([
              'order_id',
              'total_amount',
              'status'
          ]);
          
          $this->assertDatabaseHas('orders', [
              'user_id' => $user->id,
              'total_amount' => 200000
          ]);
          
          // 庫存減少
          expect($product->fresh()->stock)->toBe(8);
      });
      
      test('庫存為 0 時無法下單', function () {
          $user = User::factory()->create();
          $product = Product::factory()->create(['stock' => 0]);
          
          $response = $this->actingAs($user)
              ->post('/orders', [
                  'product_id' => $product->id,
                  'quantity' => 1
              ]);
          
          $response->assertStatus(422);
          $response->assertJsonValidationErrors(['product_id']);
      });
      
      test('未登錄用戶無法下單', function () {
          $product = Product::factory()->create();
          
          $response = $this->post('/orders', [
              'product_id' => $product->id,
              'quantity' => 1
          ]);
          
          $response->assertStatus(401);
      });
      

      常用測試命令

      # 跑全部測試
      php artisan test
      
      # Pest 可執(zhí)行文件
      ./vendor/bin/pest
      
      # 跑指定測試
      php artisan test --filter OrderTest
      
      # 生成覆蓋率
      php artisan test --coverage
      

      用 Vite 管理前端資源

      Laravel 9+ 默認(rèn)的 Vite 設(shè)置

      如果項目里還沒有,先安裝依賴:

      npm install
      

      vite.config.js

      import { defineConfig } from 'vite';
      import laravel from 'laravel-vite-plugin';
      
      export default defineConfig({
          plugins: [
              laravel({
                  input: [
                      'resources/css/app.css',
                      'resources/js/app.js',
                  ],
                  refresh: true,
              }),
          ],
      
          server: {
              host: '0.0.0.0',
              hmr: {
                  host: 'localhost',
              },
          },
      });
      

      Blade 模板里引入:

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>{{ config('app.name') }}</title>
          
          {{-- ? 就這句最簡單 --}}
          @vite(['resources/css/app.css', 'resources/js/app.js'])
      </head>
      <body>
          <!-- Content -->
      </body>
      </html>
      

      必備命令

      # 開發(fā)調(diào)試(熱更新)
      npm run dev
      
      # 構(gòu)建生產(chǎn)包(壓縮優(yōu)化)
      npm run build
      
      # 預(yù)覽生產(chǎn)包
      npm run preview
      

      總結(jié):最好的投資,就是起步時的扎實準(zhǔn)備

      項目初期多花點時間打基礎(chǔ),看似慢,其實能省掉后面一堆返工。

      好代碼不是一次成型,而是不斷打磨出來的。沒人一上來就完美無缺,真正重要的是:

      • 先把地基打牢:項目初始設(shè)置要到位。
      • 持續(xù)迭代:定期重構(gòu)、優(yōu)化。
      • 從錯誤里學(xué)習(xí):每個 Bug 都是提醒。
      • 保持更新:框架一直在進化。

      現(xiàn)在就打開你的 Laravel 項目,逐條打勾看看這 10 項設(shè)置落實了多少。如果還一項沒做,先從最關(guān)鍵的兩個開始:外鍵約束Service 層架構(gòu)。

      posted @ 2025-10-30 08:52  JaguarJack  閱讀(149)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 熟女一区二区中文字幕| 国产成人无码av一区二区| 性无码专区无码| 久久久久成人精品无码中文字幕| 日韩午夜无码精品试看| av无码一区二区大桥久未| 亚洲国产精品综合一区二区| 图片区偷拍区小说区五月 | 亚洲av免费成人精品区| 亚洲精品日韩在线观看| 嘉定区| 亚洲国产码专区在线观看| 少妇高潮惨叫喷水在线观看| 日韩中文日韩中文字幕亚| 无码国产偷倩在线播放| 国产a在视频线精品视频下载| 无码av免费毛片一区二区| 日韩一级伦理片一区二区| 亚洲精品日本一区二区| 亚洲大尺度无码专区尤物| 天天躁夜夜躁狠狠喷水| 公与淑婷厨房猛烈进出视频免费 | 97se亚洲综合在线天天| 国产精品女视频一区二区| 欧美特级午夜一区二区三区| 国产在线国偷精品产拍| 饥渴的熟妇张开腿呻吟视频| 久久夜色噜噜噜亚洲av| 亚洲中文精品久久久久久不卡 | 午夜福利国产区在线观看| 亚洲AV国产福利精品在现观看| 亚洲日韩国产精品第一页一区| 亚洲av精彩一区二区| 狠狠cao日日穞夜夜穞av| 国产粉嫩系列一区二区三| 久久精品99国产国产精| 不卡一区二区三区四区视频| 日韩在线观看精品亚洲| 东方av四虎在线观看| 免费观看日本污污ww网站69| 91久久性奴调教国产免费|