{"id":3285,"date":"2025-03-24T08:46:31","date_gmt":"2025-03-23T23:46:31","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=3285"},"modified":"2025-03-24T08:47:01","modified_gmt":"2025-03-23T23:47:01","slug":"%e3%80%90laravel%e5%85%a5%e9%96%80%e3%80%91%e3%83%87%e3%83%bc%e3%82%bf%e3%83%99%e3%83%bc%e3%82%b9%e6%a4%9c%e7%b4%a2%e6%a9%9f%e8%83%bd%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b%e5%ae%8c%e5%85%a8","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=3285","title":{"rendered":"\u3010Laravel\u5165\u9580\u3011\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u5b8c\u5168\u30ac\u30a4\u30c92024 \u301c \u521d\u5fc3\u8005\u3067\u3082\u308f\u304b\u308b7\u3064\u306e\u5b9f\u88c5\u624b\u6cd5"},"content":{"rendered":"\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">Laravel\u3067\u4f5c\u308b\u691c\u7d22\u6a5f\u80fd\u306e\u57fa\u790e\u77e5\u8b58<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">Laravel\u306e\u691c\u7d22\u6a5f\u80fd\u306b\u5fc5\u8981\u306a\u4e3b\u8981\u8981\u7d20<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-2\">\u691c\u7d22\u6a5f\u80fd\u5b9f\u88c5\u524d\u306b\u62bc\u3055\u3048\u3066\u304a\u304f\u3079\u304d\u8a2d\u8a08\u306e\u30dd\u30a4\u30f3\u30c8<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-3\">\u30b7\u30f3\u30d7\u30eb\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u624b\u9806\u5b9f\u88c5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-4\">Eloquent\u3092\u4f7f\u3063\u305f\u57fa\u672c\u7684\u306a\u691c\u7d22\u30af\u30a8\u30ea\u306e\u66f8\u304d\u65b9<\/a>      <\/li>      <li>        <a href=\"#i-5\">\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u306e\u4f5c\u6210\u3068\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u8a2d\u5b9a\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-6\">\u691c\u7d22\u7d50\u679c\u306e\u8868\u793a\u65b9\u6cd5\u3068\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u73fe<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-7\">\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u30c6\u30af\u30cb\u30c3\u30af<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-8\">\u8907\u6570\u306e\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u691c\u7d22\u6a5f\u80fd\u306e\u4f5c\u308a\u65b9<\/a>      <\/li>      <li>        <a href=\"#i-9\">\u90e8\u5206\u4e00\u81f4\u691c\u7d22\u3068\u3042\u3044\u307e\u3044\u691c\u7d22\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-10\">\u30b9\u30b3\u30fc\u30d7\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u306e\u6700\u9069\u5316\u624b\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-11\">\u691c\u7d22\u6a5f\u80fd\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-12\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u901f\u5ea6\u306e\u5411\u4e0a\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-13\">N+1 \u554f\u984c\u3092\u89e3\u6c7a\u3059\u308b EagerLoading \u306e\u5b9f\u88c5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-14\">\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u4f7f\u3063\u305f\u691c\u7d22\u7d50\u679c\u306e\u6700\u9069\u5316\u30c6\u30af\u30cb\u30c3\u30af<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-15\">\u5b9f\u8df5\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-16\">Ajax\u691c\u7d22\u306e\u5b9f\u88c5\u65b9\u6cd5\u3068\u30e9\u30a4\u30d6\u691c\u7d22\u306e\u4f5c\u308a\u65b9<\/a>      <\/li>      <li>        <a href=\"#i-17\">\u691c\u7d22\u5c65\u6b74\u6a5f\u80fd\u306e\u8ffd\u52a0\u624b\u9806<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-18\">\u691c\u7d22\u7d50\u679c\u306e\u30bd\u30fc\u30c8\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-19\">\u691c\u7d22\u6a5f\u80fd\u306e\u30c6\u30b9\u30c8\u3068\u4fdd\u5b88<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-20\">PHPUnit\u3092\u4f7f\u3063\u305f\u691c\u7d22\u6a5f\u80fd\u306e\u30c6\u30b9\u30c8\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-21\">\u4e00\u822c\u7684\u306a\u30d0\u30b0\u3068\u5bfe\u51e6\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-22\">\u5c06\u6765\u306e\u6a5f\u80fd\u62e1\u5f35\u306b\u5099\u3048\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08\u306e\u30dd\u30a4\u30f3\u30c8<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-23\">Laravel \u306e\u691c\u7d22\u6a5f\u80fd\u3092\u5f37\u5316\u3059\u308b\u5916\u90e8\u30d1\u30c3\u30b1\u30fc\u30b8<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-24\">Scout \u5c0e\u5165\u306b\u3088\u308b\u5168\u6587\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-25\">Elasticsearch \u3068\u306e\u9023\u643a\u624b\u9806<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-26\">\u304a\u3059\u3059\u3081\u306e\u691c\u7d22\u95a2\u9023\u30d1\u30c3\u30b1\u30fc\u30b8\u3068\u9078\u5b9a\u57fa\u6e96<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">Laravel\u3067\u4f5c\u308b\u691c\u7d22\u6a5f\u80fd\u306e\u57fa\u790e\u77e5\u8b58<\/h2>\n\n\n\n<p>Laravel\u3067\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u969b\u306b\u3001\u307e\u305a\u306f\u57fa\u672c\u7684\u306a\u8981\u7d20\u3068\u8a2d\u8a08\u306e\u30dd\u30a4\u30f3\u30c8\u3092\u62bc\u3055\u3048\u3066\u304a\u304f\u3053\u3068\u304c\u91cd\u8981\u3067\u3059\u3002\u3053\u306e\u7ae0\u3067\u306f\u3001\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u306b\u5fc5\u8981\u306a\u57fa\u790e\u77e5\u8b58\u3092\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-1\">Laravel\u306e\u691c\u7d22\u6a5f\u80fd\u306b\u5fc5\u8981\u306a\u4e3b\u8981\u8981\u7d20<\/h3>\n\n\n\n<p>Laravel \u3067\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u969b\u306b\u306f\u3001\u4ee5\u4e0b\u306e\u4e3b\u8981\u306a\u8981\u7d20\u304c\u5fc5\u8981\u3068\u306a\u308a\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e2\u30c7\u30eb\uff08Model\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Eloquent ORM \u3092\u4f7f\u7528\u3057\u305f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3068\u306e\u3084\u308a\u53d6\u308a<\/li>\n\n\n\n<li>\u691c\u7d22\u7528\u306e\u30b9\u30b3\u30fc\u30d7\uff08scope\uff09\u30e1\u30bd\u30c3\u30c9\u306e\u5b9a\u7fa9<\/li>\n\n\n\n<li>\u30ea\u30ec\u30fc\u30b7\u30e7\u30f3\u30b7\u30c3\u30d7\u306e\u8a2d\u5b9a<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\uff08Controller\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u53d7\u3051\u53d6\u308a\u3068\u51e6\u7406<\/li>\n\n\n\n<li>\u691c\u7d22\u6761\u4ef6\u306e\u69cb\u7bc9<\/li>\n\n\n\n<li>\u691c\u7d22\u7d50\u679c\u306e\u8fd4\u5374<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d3\u30e5\u30fc\uff08View\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u306e\u8868\u793a<\/li>\n\n\n\n<li>\u691c\u7d22\u7d50\u679c\u306e\u8868\u793a<\/li>\n\n\n\n<li>\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u88c5<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30eb\u30fc\u30c8\uff08Route\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u7528\u306e\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u5b9a\u7fa9<\/li>\n\n\n\n<li>\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u3068\u7d50\u679c\u8868\u793a\u306e\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-2\">\u691c\u7d22\u6a5f\u80fd\u5b9f\u88c5\u524d\u306b\u62bc\u3055\u3048\u3066\u304a\u304f\u3079\u304d\u8a2d\u8a08\u306e\u30dd\u30a4\u30f3\u30c8<\/h3>\n\n\n\n<p>\u52b9\u7387\u7684\u3067\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u305f\u3081\u306b\u3001\u4ee5\u4e0b\u306e\u8a2d\u8a08\u30dd\u30a4\u30f3\u30c8\u3092\u62bc\u3055\u3048\u3066\u304a\u304f\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u691c\u7d22\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u8a2d\u8a08<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30af\u30a8\u30ea\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u547d\u540d\u898f\u5247\u306e\u7d71\u4e00<\/li>\n\n\n\n<li>\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u30eb\u30fc\u30eb\u306e\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u306e\u9069\u5207\u306a\u8a2d\u5b9a<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3078\u306e\u914d\u616e<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u9069\u5207\u306a\u8a2d\u5b9a<\/li>\n\n\n\n<li>N+1\u554f\u984c\u306e\u56de\u907f<\/li>\n\n\n\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565\u306e\u691c\u8a0e<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56<\/li>\n\n\n\n<li>XSS\u5bfe\u7b56<\/li>\n\n\n\n<li>CSRF\u5bfe\u7b56<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u3068\u62e1\u5f35\u6027<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8cac\u52d9\u306e\u5206\u96e2\uff08SRP\u539f\u5247\u306e\u9075\u5b88\uff09<\/li>\n\n\n\n<li>\u5171\u901a\u51e6\u7406\u306e\u62bd\u51fa<\/li>\n\n\n\n<li>\u30c6\u30b9\u30c8\u306e\u5bb9\u6613\u6027<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30d3\u30ea\u30c6\u30a3<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u6761\u4ef6\u306e\u4fdd\u6301<\/li>\n\n\n\n<li>\u691c\u7d22\u5c65\u6b74\u306e\u7ba1\u7406<\/li>\n\n\n\n<li>\u30a8\u30e9\u30fc\u51e6\u7406\u3068\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u8981\u7d20\u3068\u8a2d\u8a08\u30dd\u30a4\u30f3\u30c8\u3092\u7406\u89e3\u3057\u305f\u4e0a\u3067\u5b9f\u88c5\u3092\u9032\u3081\u308b\u3053\u3068\u3067\u3001\u3088\u308a\u5805\u7262\u3067\u4f7f\u3044\u3084\u3059\u3044\u691c\u7d22\u6a5f\u80fd\u3092\u4f5c\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u6b21\u7ae0\u3067\u306f\u3001\u3053\u308c\u3089\u306e\u77e5\u8b58\u3092\u57fa\u306b\u3001\u5b9f\u969b\u306e\u30b3\u30fc\u30c9\u3092\u4f7f\u3063\u3066\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-3\">\u30b7\u30f3\u30d7\u30eb\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u624b\u9806\u5b9f\u88c5<\/h2>\n\n\n\n<p>\u5b9f\u969b\u306bLaravel\u3067\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304f\u624b\u9806\u3092\u3001\u5177\u4f53\u7684\u306a\u30b3\u30fc\u30c9\u4f8b\u3092\u4ea4\u3048\u3066\u89e3\u8aac\u3057\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u5546\u54c1\u691c\u7d22\u3092\u4f8b\u306b\u3001\u540d\u524d\u306b\u3088\u308b\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-4\">Eloquent\u3092\u4f7f\u3063\u305f\u57fa\u672c\u7684\u306a\u691c\u7d22\u30af\u30a8\u30ea\u306e\u66f8\u304d\u65b9<\/h3>\n\n\n\n<p>\u307e\u305a\u3001\u5546\u54c1\uff08Product\uff09\u30e2\u30c7\u30eb\u3092\u4f5c\u6210\u3057\u3001\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Models\/Product.php\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Product extends Model\n{\n    protected $fillable = [\n        'name',\n        'description',\n        'price',\n        'category_id'\n    ];\n\n    \/\/ \u691c\u7d22\u7528\u306e\u30b9\u30b3\u30fc\u30d7\u3092\u5b9a\u7fa9\n    public function scopeSearch($query, $keyword)\n    {\n        \/\/ \u30ad\u30fc\u30ef\u30fc\u30c9\u304c\u7a7a\u306e\u5834\u5408\u306f\u5168\u4ef6\u53d6\u5f97\n        if (empty($keyword)) {\n            return $query;\n        }\n\n        \/\/ \u540d\u524d\u3067\u90e8\u5206\u4e00\u81f4\u691c\u7d22\n        return $query-&gt;where('name', 'like', \"%{$keyword}%\");\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u306e\u4f5c\u6210\u3068\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u8a2d\u5b9a\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u306e\u4f5c\u6210\u3068\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u8a2d\u5b9a\u3092\u884c\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/web.php\nRoute::get('\/products', [ProductController::class, 'index'])-&gt;name('products.index');<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- resources\/views\/products\/index.blade.php --&gt;\n&lt;form action=\"{{ route('products.index') }}\" method=\"GET\" class=\"mb-4\"&gt;\n    &lt;div class=\"flex items-center\"&gt;\n        &lt;input\n            type=\"text\"\n            name=\"keyword\"\n            value=\"{{ request('keyword') }}\"\n            class=\"border-gray-300 rounded-md shadow-sm\"\n            placeholder=\"\u5546\u54c1\u540d\u3092\u5165\u529b\"\n        &gt;\n        &lt;button type=\"submit\" class=\"ml-2 px-4 py-2 bg-blue-500 text-white rounded-md\"&gt;\n            \u691c\u7d22\n        &lt;\/button&gt;\n    &lt;\/div&gt;\n&lt;\/form&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-6\">\u691c\u7d22\u7d50\u679c\u306e\u8868\u793a\u65b9\u6cd5\u3068\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u73fe<\/h3>\n\n\n\n<p>\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3067\u691c\u7d22\u51e6\u7406\u3092\u5b9f\u88c5\u3057\u3001\u7d50\u679c\u3092\u8868\u793a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\Product;\nuse Illuminate\\Http\\Request;\n\nclass ProductController extends Controller\n{\n    public function index(Request $request)\n    {\n        \/\/ \u691c\u7d22\u30ad\u30fc\u30ef\u30fc\u30c9\u3092\u53d6\u5f97\n        $keyword = $request-&gt;input('keyword');\n\n        \/\/ \u30af\u30a8\u30ea\u306e\u5b9f\u884c\u3068\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\n        $products = Product::search($keyword)\n            -&gt;orderBy('created_at', 'desc')\n            -&gt;paginate(10);\n\n        \/\/ \u30d3\u30e5\u30fc\u306b\u5909\u6570\u3092\u6e21\u3057\u3066\u8868\u793a\n        return view('products.index', [\n            'products' =&gt; $products,\n            'keyword' =&gt; $keyword,\n        ]);\n    }\n}<\/pre>\n\n\n\n<p>\u691c\u7d22\u7d50\u679c\u306e\u8868\u793a\u90e8\u5206\u3092\u5b9f\u88c5\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- resources\/views\/products\/index.blade.php --&gt;\n&lt;div class=\"mt-4\"&gt;\n    @if($products-&gt;isEmpty())\n        &lt;p&gt;\u691c\u7d22\u7d50\u679c\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002&lt;\/p&gt;\n    @else\n        &lt;div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\"&gt;\n            @foreach($products as $product)\n                &lt;div class=\"border rounded-lg p-4\"&gt;\n                    &lt;h3 class=\"text-lg font-semibold\"&gt;{{ $product-&gt;name }}&lt;\/h3&gt;\n                    &lt;p class=\"text-gray-600\"&gt;{{ $product-&gt;description }}&lt;\/p&gt;\n                    &lt;p class=\"text-blue-600 font-bold\"&gt;\u00a5{{ number_format($product-&gt;price) }}&lt;\/p&gt;\n                &lt;\/div&gt;\n            @endforeach\n        &lt;\/div&gt;\n\n        &lt;!-- \u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u30ea\u30f3\u30af\u306e\u8868\u793a --&gt;\n        &lt;div class=\"mt-4\"&gt;\n            {{ $products-&gt;withQueryString()-&gt;links() }}\n        &lt;\/div&gt;\n    @endif\n&lt;\/div&gt;<\/pre>\n\n\n\n<p>\u3053\u306e\u30b3\u30fc\u30c9\u306b\u3088\u3063\u3066\u5b9f\u73fe\u3055\u308c\u308b\u6a5f\u80fd\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5546\u54c1\u540d\u306b\u3088\u308b\u90e8\u5206\u4e00\u81f4\u691c\u7d22<\/li>\n\n\n\n<li>\u691c\u7d22\u30ad\u30fc\u30ef\u30fc\u30c9\u304c\u7a7a\u306e\u5834\u5408\u306f\u5168\u4ef6\u8868\u793a<\/li>\n\n\n\n<li>\u691c\u7d22\u6761\u4ef6\u306e\u4fdd\u6301<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30d3\u30ea\u30c6\u30a3\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u30d5\u30a9\u30fc\u30e0\u306e\u5165\u529b\u5024\u4fdd\u6301<\/li>\n\n\n\n<li>\u691c\u7d22\u7d50\u679c\u304c0\u4ef6\u306e\u5834\u5408\u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u8868\u793a<\/li>\n\n\n\n<li>\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u306a\u30b0\u30ea\u30c3\u30c9\u30ec\u30a4\u30a2\u30a6\u30c8<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u6a5f\u80fd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>10\u4ef6\u3054\u3068\u306e\u30da\u30fc\u30b8\u5206\u5272<\/li>\n\n\n\n<li>\u691c\u7d22\u6761\u4ef6\u3092\u4fdd\u6301\u3057\u305f\u307e\u307e\u306e\u30da\u30fc\u30b8\u9077\u79fb<\/li>\n\n\n\n<li>\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u30ea\u30f3\u30af\u306e\u8868\u793a<\/li>\n<\/ul>\n\n\n\n<p>\u4ee5\u4e0a\u306e\u5b9f\u88c5\u306b\u3088\u308a\u3001\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u6301\u3064\u5546\u54c1\u4e00\u89a7\u30da\u30fc\u30b8\u304c\u5b8c\u6210\u3057\u307e\u3059\u3002\u6b21\u7ae0\u3067\u306f\u3001\u3053\u306e\u57fa\u672c\u5b9f\u88c5\u3092\u30d9\u30fc\u30b9\u306b\u3001\u3088\u308a\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-7\">\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u30c6\u30af\u30cb\u30c3\u30af<\/h2>\n\n\n\n<p>\u57fa\u672c\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u62e1\u5f35\u3057\u3066\u3001\u3088\u308a\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u3001\u8907\u6570\u6761\u4ef6\u306e\u7d44\u307f\u5408\u308f\u305b\u3001\u3042\u3044\u307e\u3044\u691c\u7d22\u3001\u305d\u3057\u3066\u30af\u30a8\u30ea\u30b9\u30b3\u30fc\u30d7\u3092\u6d3b\u7528\u3057\u305f\u5b9f\u88c5\u30c6\u30af\u30cb\u30c3\u30af\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-8\">\u8907\u6570\u306e\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u691c\u7d22\u6a5f\u80fd\u306e\u4f5c\u308a\u65b9<\/h3>\n\n\n\n<p>\u8907\u6570\u306e\u691c\u7d22\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Models\/Product.php\nclass Product extends Model\n{\n    public function scopeAdvancedSearch($query, array $conditions)\n    {\n        return $query-&gt;when($conditions['keyword'] ?? null, function ($query, $keyword) {\n            $query-&gt;where(function ($query) use ($keyword) {\n                $query-&gt;where('name', 'like', \"%{$keyword}%\")\n                      -&gt;orWhere('description', 'like', \"%{$keyword}%\");\n            });\n        })\n        -&gt;when($conditions['category_id'] ?? null, function ($query, $categoryId) {\n            $query-&gt;where('category_id', $categoryId);\n        })\n        -&gt;when($conditions['price_min'] ?? null, function ($query, $minPrice) {\n            $query-&gt;where('price', '&gt;=', $minPrice);\n        })\n        -&gt;when($conditions['price_max'] ?? null, function ($query, $maxPrice) {\n            $query-&gt;where('price', '&lt;=', $maxPrice);\n        })\n        -&gt;when($conditions['in_stock'] ?? null, function ($query) {\n            $query-&gt;where('stock', '&gt;', 0);\n        });\n    }\n}<\/pre>\n\n\n\n<p>\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3067\u306e\u5b9f\u88c5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\npublic function search(Request $request)\n{\n    $conditions = $request-&gt;validate([\n        'keyword' =&gt; 'nullable|string|max:100',\n        'category_id' =&gt; 'nullable|exists:categories,id',\n        'price_min' =&gt; 'nullable|numeric|min:0',\n        'price_max' =&gt; 'nullable|numeric|gt:price_min',\n        'in_stock' =&gt; 'nullable|boolean'\n    ]);\n\n    $products = Product::advancedSearch($conditions)\n        -&gt;with('category')  \/\/ Eager Loading\n        -&gt;orderBy('created_at', 'desc')\n        -&gt;paginate(15);\n\n    return view('products.search', compact('products', 'conditions'));\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">\u90e8\u5206\u4e00\u81f4\u691c\u7d22\u3068\u3042\u3044\u307e\u3044\u691c\u7d22\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u3088\u308a\u67d4\u8edf\u306a\u691c\u7d22\u3092\u5b9f\u73fe\u3059\u308b\u305f\u3081\u306e\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Models\/Product.php\nclass Product extends Model\n{\n    public function scopeFuzzySearch($query, $keyword)\n    {\n        \/\/ \u30ad\u30fc\u30ef\u30fc\u30c9\u3092\u5206\u5272\u3057\u3066\u914d\u5217\u5316\n        $keywords = preg_split('\/[\\s\u3000]+\/u', $keyword, -1, PREG_SPLIT_NO_EMPTY);\n\n        return $query-&gt;where(function ($query) use ($keywords) {\n            foreach ($keywords as $keyword) {\n                $query-&gt;where(function ($query) use ($keyword) {\n                    \/\/ \u540d\u524d\u3001\u8aac\u660e\u6587\u3001\u5546\u54c1\u30b3\u30fc\u30c9\u3067\u691c\u7d22\n                    $query-&gt;where('name', 'like', \"%{$keyword}%\")\n                          -&gt;orWhere('description', 'like', \"%{$keyword}%\")\n                          -&gt;orWhere('product_code', 'like', \"%{$keyword}%\");\n                });\n            }\n        });\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-10\">\u30b9\u30b3\u30fc\u30d7\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u306e\u6700\u9069\u5316\u624b\u6cd5<\/h3>\n\n\n\n<p>\u691c\u7d22\u6a5f\u80fd\u3092\u52b9\u7387\u7684\u306b\u5b9f\u88c5\u30fb\u7ba1\u7406\u3059\u308b\u305f\u3081\u306e\u30b9\u30b3\u30fc\u30d7\u30d1\u30bf\u30fc\u30f3\u3092\u7d39\u4ecb\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Models\/Product.php\nclass Product extends Model\n{\n    \/\/ \u4fa1\u683c\u5e2f\u306b\u3088\u308b\u691c\u7d22\n    public function scopePriceRange($query, $min, $max)\n    {\n        return $query-&gt;when($min, fn($q) =&gt; $q-&gt;where('price', '&gt;=', $min))\n                    -&gt;when($max, fn($q) =&gt; $q-&gt;where('price', '&lt;=', $max));\n    }\n\n    \/\/ \u30ab\u30c6\u30b4\u30ea\u30fc\u306b\u3088\u308b\u691c\u7d22\n    public function scopeInCategories($query, $categoryIds)\n    {\n        return $query-&gt;whereIn('category_id', (array)$categoryIds);\n    }\n\n    \/\/ \u5728\u5eab\u72b6\u6cc1\u306b\u3088\u308b\u691c\u7d22\n    public function scopeStockStatus($query, $status)\n    {\n        return match ($status) {\n            'in_stock' =&gt; $query-&gt;where('stock', '&gt;', 0),\n            'out_of_stock' =&gt; $query-&gt;where('stock', '&lt;=', 0),\n            'low_stock' =&gt; $query-&gt;where('stock', '&gt;', 0)\n                                -&gt;where('stock', '&lt;=', 5),\n            default =&gt; $query\n        };\n    }\n\n    \/\/ \u691c\u7d22\u6761\u4ef6\u306e\u7d44\u307f\u5408\u308f\u305b\u4f8b\n    public function scopeFilterByConditions($query, array $conditions)\n    {\n        return $query-&gt;when($conditions['keyword'] ?? null, \n                          fn($q, $keyword) =&gt; $q-&gt;fuzzySearch($keyword))\n                    -&gt;when($conditions['price'] ?? null, \n                          fn($q) =&gt; $q-&gt;priceRange(\n                              $conditions['price']['min'] ?? null,\n                              $conditions['price']['max'] ?? null\n                          ))\n                    -&gt;when($conditions['categories'] ?? null,\n                          fn($q) =&gt; $q-&gt;inCategories($conditions['categories']))\n                    -&gt;when($conditions['stock_status'] ?? null,\n                          fn($q) =&gt; $q-&gt;stockStatus($conditions['stock_status']));\n    }\n}<\/pre>\n\n\n\n<p>\u3053\u306e\u3088\u3046\u306b\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3067\u5f97\u3089\u308c\u308b\u5229\u70b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u30ed\u30b8\u30c3\u30af\u304c\u30e2\u30c7\u30eb\u306b\u96c6\u7d04\u3055\u308c\u308b<\/li>\n\n\n\n<li>\u30b9\u30b3\u30fc\u30d7\u306e\u7d44\u307f\u5408\u308f\u305b\u306b\u3088\u308b\u67d4\u8edf\u306a\u691c\u7d22\u6761\u4ef6\u306e\u69cb\u7bc9<\/li>\n\n\n\n<li>\u30b3\u30fc\u30c9\u306e\u518d\u5229\u7528\u6027\u306e\u5411\u4e0a<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u53ef\u8aad\u6027\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u6761\u4ef6\u3054\u3068\u306b\u30b9\u30b3\u30fc\u30d7\u304c\u5206\u96e2\u3055\u308c\u308b<\/li>\n\n\n\n<li>\u610f\u56f3\u304c\u660e\u78ba\u306a\u547d\u540d\u306b\u3088\u308b\u7406\u89e3\u306e\u3057\u3084\u3059\u3055<\/li>\n\n\n\n<li>\u30c1\u30a7\u30fc\u30f3\u30e1\u30bd\u30c3\u30c9\u306b\u3088\u308b\u76f4\u611f\u7684\u306a\u4f7f\u7528\u65b9\u6cd5<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u62e1\u5f35\u6027\u306e\u78ba\u4fdd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u65b0\u3057\u3044\u691c\u7d22\u6761\u4ef6\u306e\u8ffd\u52a0\u304c\u5bb9\u6613<\/li>\n\n\n\n<li>\u65e2\u5b58\u306e\u691c\u7d22\u6761\u4ef6\u306e\u4fee\u6b63\u304c\u5c40\u6240\u7684<\/li>\n\n\n\n<li>\u30c6\u30b9\u30c8\u304c\u66f8\u304d\u3084\u3059\u3044\u69cb\u9020<\/li>\n<\/ul>\n\n\n\n<p>\u6b21\u7ae0\u3067\u306f\u3001\u3053\u308c\u3089\u306e\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u88c5\u3059\u308b\u969b\u306e\u6027\u80fd\u6700\u9069\u5316\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-11\">\u691c\u7d22\u6a5f\u80fd\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316<\/h2>\n\n\n\n<p>\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u5f8c\u3001\u30e6\u30fc\u30b6\u30fc\u6570\u3084\u691c\u7d22\u5bfe\u8c61\u306e\u30c7\u30fc\u30bf\u91cf\u304c\u5897\u52a0\u3059\u308b\u3068\u3001\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306e\u554f\u984c\u304c\u9855\u5728\u5316\u3057\u3066\u304d\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u3001Laravel\u691c\u7d22\u6a5f\u80fd\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u6700\u9069\u5316\u3059\u308b\u305f\u3081\u306e\u5177\u4f53\u7684\u306a\u624b\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-12\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u901f\u5ea6\u306e\u5411\u4e0a\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u9069\u5207\u306b\u8a2d\u5b9a\u3059\u308b\u3053\u3068\u3067\u3001\u691c\u7d22\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u5927\u304d\u304f\u6539\u5584\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ database\/migrations\/2024_02_19_create_products_table.php\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    public function up()\n    {\n        Schema::create('products', function (Blueprint $table) {\n            $table-&gt;id();\n            $table-&gt;string('name');\n            $table-&gt;text('description');\n            $table-&gt;decimal('price', 10, 2);\n            $table-&gt;integer('category_id');\n            $table-&gt;integer('stock');\n            $table-&gt;timestamps();\n\n            \/\/ \u5358\u4e00\u30ab\u30e9\u30e0\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\n            $table-&gt;index('name');\n            $table-&gt;index('category_id');\n            $table-&gt;index('price');\n\n            \/\/ \u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\n            $table-&gt;index(['category_id', 'price']);\n        });\n    }\n};<\/pre>\n\n\n\n<p>\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8a2d\u8a08\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u983b\u7e41\u306b\u691c\u7d22\u3055\u308c\u308b\u5217\u306b\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u4f5c\u6210<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u65e2\u5b58\u30c6\u30fc\u30d6\u30eb\u3078\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8ffd\u52a0\n   public function up()\n   {\n       Schema::table('products', function (Blueprint $table) {\n           \/\/ \u691c\u7d22\u983b\u5ea6\u306e\u9ad8\u3044\u5217\u306b\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u8ffd\u52a0\n           $table-&gt;index(['name', 'category_id', 'price']);\n       });\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u4e0d\u8981\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u524a\u9664<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   public function down()\n   {\n       Schema::table('products', function (Blueprint $table) {\n           $table-&gt;dropIndex(['name', 'category_id', 'price']);\n       });\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">N+1 \u554f\u984c\u3092\u89e3\u6c7a\u3059\u308b EagerLoading \u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>N+1\u554f\u984c\u306f\u691c\u7d22\u6a5f\u80fd\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8457\u3057\u304f\u4f4e\u4e0b\u3055\u305b\u308b\u4e3b\u8981\u306a\u539f\u56e0\u306e\u4e00\u3064\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\nclass ProductController extends Controller\n{\n    public function index(Request $request)\n    {\n        \/\/ \u60aa\u3044\u4f8b\uff08N+1\u554f\u984c\u767a\u751f\uff09\n        $products = Product::search($request-&gt;keyword)-&gt;paginate(10);\n\n        \/\/ \u826f\u3044\u4f8b\uff08Eager Loading\u3067\u89e3\u6c7a\uff09\n        $products = Product::search($request-&gt;keyword)\n            -&gt;with(['category', 'brand', 'reviews'])  \/\/ \u30ea\u30ec\u30fc\u30b7\u30e7\u30f3\u5148\u3092\u4e8b\u524d\u8aad\u307f\u8fbc\u307f\n            -&gt;paginate(10);\n\n        return view('products.index', compact('products'));\n    }\n\n    \/\/ \u6761\u4ef6\u4ed8\u304dEager Loading\n    public function advancedSearch(Request $request)\n    {\n        $products = Product::query()\n            -&gt;with(['category', 'brand'])\n            -&gt;when($request-&gt;include_reviews, function ($query) {\n                $query-&gt;with(['reviews' =&gt; function ($query) {\n                    $query-&gt;latest()-&gt;limit(5);\n                }]);\n            })\n            -&gt;search($request-&gt;keyword)\n            -&gt;paginate(15);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-14\">\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u4f7f\u3063\u305f\u691c\u7d22\u7d50\u679c\u306e\u6700\u9069\u5316\u30c6\u30af\u30cb\u30c3\u30af<\/h3>\n\n\n\n<p>\u983b\u7e41\u306b\u5b9f\u884c\u3055\u308c\u308b\u691c\u7d22\u3084\u3001\u8a08\u7b97\u30b3\u30b9\u30c8\u306e\u9ad8\u3044\u691c\u7d22\u7d50\u679c\u3092\u30ad\u30e3\u30c3\u30b7\u30e5\u3059\u308b\u3053\u3068\u3067\u3001\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\nuse Illuminate\\Support\\Facades\\Cache;\n\nclass ProductController extends Controller\n{\n    public function search(Request $request)\n    {\n        \/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u30ad\u30fc\u306e\u751f\u6210\n        $cacheKey = 'search_' . md5(json_encode($request-&gt;all()));\n\n        \/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u304b\u3089\u7d50\u679c\u3092\u53d6\u5f97\u3001\u306a\u3051\u308c\u3070DB\u304b\u3089\u53d6\u5f97\u3057\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\n        $products = Cache::remember($cacheKey, now()-&gt;addMinutes(30), function () use ($request) {\n            return Product::search($request-&gt;keyword)\n                -&gt;with(['category', 'brand'])\n                -&gt;paginate(15);\n        });\n\n        return view('products.search', compact('products'));\n    }\n\n    \/\/ \u3088\u308a\u9ad8\u5ea6\u306a\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565\u306e\u5b9f\u88c5\u4f8b\n    public function advancedCacheSearch(Request $request)\n    {\n        $cacheKey = $this-&gt;generateCacheKey($request);\n        $cacheTags = ['products', 'search'];\n\n        if (Cache::tags($cacheTags)-&gt;has($cacheKey)) {\n            $results = Cache::tags($cacheTags)-&gt;get($cacheKey);\n            $this-&gt;incrementSearchCount($cacheKey);\n            return $results;\n        }\n\n        $results = $this-&gt;performSearch($request);\n\n        \/\/ \u691c\u7d22\u7d50\u679c\u3092\u30ad\u30e3\u30c3\u30b7\u30e5\uff08\u4eba\u6c17\u306e\u691c\u7d22\u306f\u3088\u308a\u9577\u304f\u4fdd\u6301\uff09\n        $ttl = $this-&gt;determineCacheTTL($cacheKey);\n        Cache::tags($cacheTags)-&gt;put($cacheKey, $results, $ttl);\n\n        return $results;\n    }\n\n    private function generateCacheKey(Request $request): string\n    {\n        return sprintf(\n            'search_%s_%s_%s',\n            $request-&gt;input('keyword', ''),\n            $request-&gt;input('category', ''),\n            $request-&gt;input('sort', 'default')\n        );\n    }\n\n    private function determineCacheTTL(string $cacheKey): int\n    {\n        $searchCount = Cache::get(\"search_count_{$cacheKey}\", 0);\n\n        \/\/ \u691c\u7d22\u983b\u5ea6\u306b\u5fdc\u3058\u3066\u30ad\u30e3\u30c3\u30b7\u30e5\u6642\u9593\u3092\u8abf\u6574\n        return match (true) {\n            $searchCount &gt; 100 =&gt; 60,  \/\/ 1\u6642\u9593\n            $searchCount &gt; 50  =&gt; 30,  \/\/ 30\u5206\n            default           =&gt; 15    \/\/ 15\u5206\n        };\n    }\n}<\/pre>\n\n\n\n<p>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30af\u30a8\u30ea\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5fc5\u8981\u306a\u30ab\u30e9\u30e0\u306e\u307f\u3092\u9078\u629e<\/li>\n\n\n\n<li>\u9069\u5207\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u4f7f\u7528<\/li>\n\n\n\n<li>\u7d50\u5408\u6761\u4ef6\u306e\u6700\u9069\u5316<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9069\u5207\u306a\u30ad\u30e3\u30c3\u30b7\u30e5\u30ad\u30fc\u306e\u8a2d\u8a08<\/li>\n\n\n\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u6709\u52b9\u671f\u9650\u306e\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u7121\u52b9\u5316\u30bf\u30a4\u30df\u30f3\u30b0<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u76e3\u8996\u3068\u30c1\u30e5\u30fc\u30cb\u30f3\u30b0<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30af\u30a8\u30ea\u30ed\u30b0\u306e\u5206\u6790<\/li>\n\n\n\n<li>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306e\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0<\/li>\n\n\n\n<li>\u30dc\u30c8\u30eb\u30cd\u30c3\u30af\u306e\u7279\u5b9a\u3068\u89e3\u6d88<\/li>\n<\/ul>\n\n\n\n<p>\u6b21\u7ae0\u3067\u306f\u3001\u3053\u308c\u3089\u306e\u6700\u9069\u5316\u30c6\u30af\u30cb\u30c3\u30af\u3092\u6d3b\u7528\u3057\u305f\u5b9f\u8df5\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b\u3092\u7d39\u4ecb\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-15\">\u5b9f\u8df5\u7684\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b<\/h2>\n\n\n\n<p>\u3053\u3053\u3067\u306f\u3001\u5b9f\u969b\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u3088\u304f\u6c42\u3081\u3089\u308c\u308b\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002Ajax\u691c\u7d22\u306b\u3088\u308b\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u691c\u7d22\u3001\u691c\u7d22\u5c65\u6b74\u6a5f\u80fd\u3001\u305d\u3057\u3066\u691c\u7d22\u7d50\u679c\u306e\u30bd\u30fc\u30c8\u6a5f\u80fd\u306b\u3064\u3044\u3066\u3001\u5177\u4f53\u7684\u306a\u5b9f\u88c5\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-16\">Ajax\u691c\u7d22\u306e\u5b9f\u88c5\u65b9\u6cd5\u3068\u30e9\u30a4\u30d6\u691c\u7d22\u306e\u4f5c\u308a\u65b9<\/h3>\n\n\n\n<p>\u30e6\u30fc\u30b6\u30fc\u306e\u5165\u529b\u306b\u5fdc\u3058\u3066\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u306b\u691c\u7d22\u7d50\u679c\u3092\u8868\u793a\u3059\u308b\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/web.php\nRoute::get('\/products\/search', [ProductController::class, 'ajaxSearch'])\n    -&gt;name('products.ajax-search');\n\n\/\/ app\/Http\/Controllers\/ProductController.php\npublic function ajaxSearch(Request $request)\n{\n    $products = Product::query()\n        -&gt;when($request-&gt;keyword, function ($query, $keyword) {\n            $query-&gt;where('name', 'like', \"%{$keyword}%\");\n        })\n        -&gt;with('category')\n        -&gt;take(5)\n        -&gt;get();\n\n    return response()-&gt;json([\n        'products' =&gt; $products\n    ]);\n}<\/pre>\n\n\n\n<p>\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u5b9f\u88c5\uff08Blade\u30d3\u30e5\u30fc\uff09\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- resources\/views\/products\/search.blade.php --&gt;\n&lt;div x-data=\"liveSearch()\"&gt;\n    &lt;div class=\"relative\"&gt;\n        &lt;input\n            type=\"text\"\n            x-model=\"keyword\"\n            x-on:input.debounce.300ms=\"search()\"\n            class=\"w-full px-4 py-2 border rounded-lg\"\n            placeholder=\"\u5546\u54c1\u540d\u3092\u5165\u529b\"\n        &gt;\n\n        &lt;!-- \u691c\u7d22\u7d50\u679c\u306e\u8868\u793a\u9818\u57df --&gt;\n        &lt;div\n            x-show=\"results.length &gt; 0\"\n            class=\"absolute z-10 w-full mt-1 bg-white border rounded-lg shadow-lg\"\n        &gt;\n            &lt;template x-for=\"product in results\" :key=\"product.id\"&gt;\n                &lt;div class=\"p-2 hover:bg-gray-100 cursor-pointer\"&gt;\n                    &lt;div x-text=\"product.name\" class=\"font-medium\"&gt;&lt;\/div&gt;\n                    &lt;div x-text=\"product.price\" class=\"text-sm text-gray-600\"&gt;&lt;\/div&gt;\n                &lt;\/div&gt;\n            &lt;\/template&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;script&gt;\nfunction liveSearch() {\n    return {\n        keyword: '',\n        results: [],\n\n        async search() {\n            if (this.keyword.length &lt; 2) {\n                this.results = [];\n                return;\n            }\n\n            try {\n                const response = await fetch(`\/products\/search?keyword=${this.keyword}`);\n                const data = await response.json();\n                this.results = data.products;\n            } catch (error) {\n                console.error('\u691c\u7d22\u30a8\u30e9\u30fc:', error);\n                this.results = [];\n            }\n        }\n    }\n}\n&lt;\/script&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">\u691c\u7d22\u5c65\u6b74\u6a5f\u80fd\u306e\u8ffd\u52a0\u624b\u9806<\/h3>\n\n\n\n<p>\u30e6\u30fc\u30b6\u30fc\u306e\u691c\u7d22\u5c65\u6b74\u3092\u4fdd\u5b58\u30fb\u8868\u793a\u3059\u308b\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ database\/migrations\/2024_02_19_create_search_histories_table.php\npublic function up()\n{\n    Schema::create('search_histories', function (Blueprint $table) {\n        $table-&gt;id();\n        $table-&gt;foreignId('user_id')-&gt;constrained();\n        $table-&gt;string('keyword');\n        $table-&gt;json('filters')-&gt;nullable();\n        $table-&gt;integer('result_count');\n        $table-&gt;timestamps();\n\n        $table-&gt;index(['user_id', 'created_at']);\n    });\n}\n\n\/\/ app\/Models\/SearchHistory.php\nclass SearchHistory extends Model\n{\n    protected $fillable = ['user_id', 'keyword', 'filters', 'result_count'];\n    protected $casts = ['filters' =&gt; 'array'];\n\n    public function user()\n    {\n        return $this-&gt;belongsTo(User::class);\n    }\n}\n\n\/\/ app\/Http\/Controllers\/ProductController.php\npublic function search(Request $request)\n{\n    $products = Product::search($request-&gt;keyword)\n        -&gt;with('category')\n        -&gt;paginate(15);\n\n    \/\/ \u691c\u7d22\u5c65\u6b74\u306e\u4fdd\u5b58\n    if ($request-&gt;user()) {\n        SearchHistory::create([\n            'user_id' =&gt; $request-&gt;user()-&gt;id,\n            'keyword' =&gt; $request-&gt;keyword,\n            'filters' =&gt; $request-&gt;only(['category', 'price_range']),\n            'result_count' =&gt; $products-&gt;total()\n        ]);\n    }\n\n    \/\/ \u6700\u8fd1\u306e\u691c\u7d22\u5c65\u6b74\u3092\u53d6\u5f97\n    $recentSearches = [];\n    if ($request-&gt;user()) {\n        $recentSearches = SearchHistory::where('user_id', $request-&gt;user()-&gt;id)\n            -&gt;latest()\n            -&gt;take(5)\n            -&gt;get();\n    }\n\n    return view('products.search', compact('products', 'recentSearches'));\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-18\">\u691c\u7d22\u7d50\u679c\u306e\u30bd\u30fc\u30c8\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u8907\u6570\u306e\u6761\u4ef6\u3067\u30bd\u30fc\u30c8\u53ef\u80fd\u306a\u691c\u7d22\u7d50\u679c\u306e\u5b9f\u88c5\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\npublic function search(Request $request)\n{\n    $sortField = $request-&gt;input('sort', 'created_at');\n    $sortDirection = $request-&gt;input('direction', 'desc');\n\n    \/\/ \u8a31\u53ef\u3055\u308c\u305f\u30bd\u30fc\u30c8\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u5b9a\u7fa9\n    $allowedSortFields = [\n        'name' =&gt; 'name',\n        'price' =&gt; 'price',\n        'popularity' =&gt; 'view_count',\n        'newest' =&gt; 'created_at'\n    ];\n\n    \/\/ \u30af\u30a8\u30ea\u306e\u69cb\u7bc9\n    $products = Product::search($request-&gt;keyword)\n        -&gt;when($sortField, function ($query) use ($sortField, $sortDirection, $allowedSortFields) {\n            if (isset($allowedSortFields[$sortField])) {\n                $query-&gt;orderBy($allowedSortFields[$sortField], $sortDirection);\n            }\n        })\n        -&gt;paginate(15)\n        -&gt;appends($request-&gt;query());\n\n    return view('products.search', [\n        'products' =&gt; $products,\n        'sortField' =&gt; $sortField,\n        'sortDirection' =&gt; $sortDirection\n    ]);\n}<\/pre>\n\n\n\n<p>\u30bd\u30fc\u30c8\u6a5f\u80fd\u306e\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u5b9f\u88c5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- resources\/views\/products\/search.blade.php --&gt;\n&lt;div class=\"flex items-center justify-between mb-4\"&gt;\n    &lt;h2&gt;\u691c\u7d22\u7d50\u679c: {{ $products-&gt;total() }}\u4ef6&lt;\/h2&gt;\n\n    &lt;div class=\"flex items-center space-x-2\"&gt;\n        &lt;span class=\"text-gray-600\"&gt;\u4e26\u3073\u66ff\u3048:&lt;\/span&gt;\n        &lt;select\n            x-data\n            x-on:change=\"window.location = new URL($event.target.value, window.location.href)\"\n            class=\"border rounded-md px-2 py-1\"\n        &gt;\n            &lt;option value=\"{{ route('products.search', array_merge(request()-&gt;query(), ['sort' =&gt; 'newest'])) }}\"\n                    {{ request('sort') === 'newest' ? 'selected' : '' }}&gt;\n                \u65b0\u7740\u9806\n            &lt;\/option&gt;\n            &lt;option value=\"{{ route('products.search', array_merge(request()-&gt;query(), ['sort' =&gt; 'price', 'direction' =&gt; 'asc'])) }}\"\n                    {{ request('sort') === 'price' &amp;&amp; request('direction') === 'asc' ? 'selected' : '' }}&gt;\n                \u4fa1\u683c\u304c\u5b89\u3044\u9806\n            &lt;\/option&gt;\n            &lt;option value=\"{{ route('products.search', array_merge(request()-&gt;query(), ['sort' =&gt; 'price', 'direction' =&gt; 'desc'])) }}\"\n                    {{ request('sort') === 'price' &amp;&amp; request('direction') === 'desc' ? 'selected' : '' }}&gt;\n                \u4fa1\u683c\u304c\u9ad8\u3044\u9806\n            &lt;\/option&gt;\n            &lt;option value=\"{{ route('products.search', array_merge(request()-&gt;query(), ['sort' =&gt; 'popularity'])) }}\"\n                    {{ request('sort') === 'popularity' ? 'selected' : '' }}&gt;\n                \u4eba\u6c17\u9806\n            &lt;\/option&gt;\n        &lt;\/select&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u88c5\u306b\u3088\u3063\u3066\u5f97\u3089\u308c\u308b\u5229\u70b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30d3\u30ea\u30c6\u30a3\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u306a\u691c\u7d22\u7d50\u679c\u8868\u793a<\/li>\n\n\n\n<li>\u691c\u7d22\u5c65\u6b74\u304b\u3089\u306e\u7d20\u65e9\u3044\u518d\u691c\u7d22<\/li>\n\n\n\n<li>\u67d4\u8edf\u306a\u30bd\u30fc\u30c8\u6a5f\u80fd<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5fc5\u8981\u306a\u60c5\u5831\u306e\u307f\u3092\u975e\u540c\u671f\u3067\u53d6\u5f97<\/li>\n\n\n\n<li>\u691c\u7d22\u5c65\u6b74\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u6700\u9069\u5316<\/li>\n\n\n\n<li>\u52b9\u7387\u7684\u306a\u30bd\u30fc\u30c8\u306e\u5b9f\u88c5<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u306e\u78ba\u4fdd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8cac\u52d9\u306e\u660e\u78ba\u306a\u5206\u96e2<\/li>\n\n\n\n<li>\u518d\u5229\u7528\u53ef\u80fd\u306a\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8<\/li>\n\n\n\n<li>\u62e1\u5f35\u6027\u306e\u9ad8\u3044\u8a2d\u8a08<\/li>\n<\/ul>\n\n\n\n<p>\u6b21\u7ae0\u3067\u306f\u3001\u3053\u308c\u3089\u306e\u6a5f\u80fd\u3092\u542b\u3080\u691c\u7d22\u30b7\u30b9\u30c6\u30e0\u306e\u30c6\u30b9\u30c8\u3068\u4fdd\u5b88\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-19\">\u691c\u7d22\u6a5f\u80fd\u306e\u30c6\u30b9\u30c8\u3068\u4fdd\u5b88<\/h2>\n\n\n\n<p>\u691c\u7d22\u6a5f\u80fd\u306e\u4fe1\u983c\u6027\u3092\u78ba\u4fdd\u3057\u3001\u9577\u671f\u7684\u306a\u4fdd\u5b88\u6027\u3092\u9ad8\u3081\u308b\u305f\u3081\u306b\u306f\u3001\u9069\u5207\u306a\u30c6\u30b9\u30c8\u306e\u5b9f\u88c5\u3068\u4fdd\u5b88\u6027\u3092\u8003\u616e\u3057\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08\u304c\u4e0d\u53ef\u6b20\u3067\u3059\u3002\u3053\u3053\u3067\u306f\u3001PHPUnit\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\u65b9\u6cd5\u3084\u4e00\u822c\u7684\u306a\u30d0\u30b0\u3078\u306e\u5bfe\u51e6\u6cd5\u3001\u305d\u3057\u3066\u5c06\u6765\u306e\u6a5f\u80fd\u62e1\u5f35\u306b\u5099\u3048\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-20\">PHPUnit\u3092\u4f7f\u3063\u305f\u691c\u7d22\u6a5f\u80fd\u306e\u30c6\u30b9\u30c8\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u691c\u7d22\u6a5f\u80fd\u306e\u5404\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306b\u5bfe\u3059\u308b\u30c6\u30b9\u30c8\u306e\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ tests\/Feature\/ProductSearchTest.php\nnamespace Tests\\Feature;\n\nuse Tests\\TestCase;\nuse App\\Models\\Product;\nuse App\\Models\\Category;\nuse Illuminate\\Foundation\\Testing\\RefreshDatabase;\n\nclass ProductSearchTest extends TestCase\n{\n    use RefreshDatabase;\n\n    protected function setUp(): void\n    {\n        parent::setUp();\n\n        \/\/ \u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u6e96\u5099\n        Category::factory()-&gt;create(['name' =&gt; 'Electronics']);\n        Product::factory()-&gt;count(20)-&gt;create();\n        Product::factory()-&gt;create([\n            'name' =&gt; 'Test Product',\n            'price' =&gt; 1000,\n            'category_id' =&gt; 1\n        ]);\n    }\n\n    \/** @test *\/\n    public function it_can_search_products_by_keyword()\n    {\n        $response = $this-&gt;get('\/products\/search?keyword=Test');\n\n        $response-&gt;assertStatus(200)\n                -&gt;assertSee('Test Product')\n                -&gt;assertViewHas('products');\n    }\n\n    \/** @test *\/\n    public function it_returns_empty_results_for_non_matching_keyword()\n    {\n        $response = $this-&gt;get('\/products\/search?keyword=NonExistent');\n\n        $response-&gt;assertStatus(200)\n                -&gt;assertDontSee('Test Product')\n                -&gt;assertViewHas('products', function($products) {\n                    return $products-&gt;isEmpty();\n                });\n    }\n\n    \/** @test *\/\n    public function it_can_filter_products_by_price_range()\n    {\n        $response = $this-&gt;get('\/products\/search?price_min=500&amp;price_max=1500');\n\n        $response-&gt;assertStatus(200)\n                -&gt;assertSee('Test Product')\n                -&gt;assertViewHas('products', function($products) {\n                    return $products-&gt;every(function($product) {\n                        return $product-&gt;price &gt;= 500 &amp;&amp; $product-&gt;price &lt;= 1500;\n                    });\n                });\n    }\n\n    \/** @test *\/\n    public function it_handles_invalid_search_parameters_gracefully()\n    {\n        $response = $this-&gt;get('\/products\/search?price_min=invalid');\n\n        $response-&gt;assertStatus(302)\n                -&gt;assertSessionHasErrors('price_min');\n    }\n}\n\n\/\/ tests\/Unit\/ProductTest.php\nnamespace Tests\\Unit;\n\nuse Tests\\TestCase;\nuse App\\Models\\Product;\nuse Illuminate\\Foundation\\Testing\\RefreshDatabase;\n\nclass ProductTest extends TestCase\n{\n    use RefreshDatabase;\n\n    \/** @test *\/\n    public function it_can_scope_search_by_name()\n    {\n        Product::factory()-&gt;create(['name' =&gt; 'Test Product']);\n        Product::factory()-&gt;create(['name' =&gt; 'Another Product']);\n\n        $results = Product::search('Test')-&gt;get();\n\n        $this-&gt;assertCount(1, $results);\n        $this-&gt;assertEquals('Test Product', $results-&gt;first()-&gt;name);\n    }\n\n    \/** @test *\/\n    public function it_can_combine_multiple_search_conditions()\n    {\n        Product::factory()-&gt;create([\n            'name' =&gt; 'Test Product',\n            'price' =&gt; 1000,\n            'category_id' =&gt; 1\n        ]);\n\n        $conditions = [\n            'keyword' =&gt; 'Test',\n            'price_min' =&gt; 500,\n            'category_id' =&gt; 1\n        ];\n\n        $results = Product::advancedSearch($conditions)-&gt;get();\n\n        $this-&gt;assertCount(1, $results);\n        $this-&gt;assertEquals('Test Product', $results-&gt;first()-&gt;name);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">\u4e00\u822c\u7684\u306a\u30d0\u30b0\u3068\u5bfe\u51e6\u6cd5<\/h3>\n\n\n\n<p>\u691c\u7d22\u6a5f\u80fd\u3067\u767a\u751f\u3057\u3084\u3059\u3044\u554f\u984c\u3068\u305d\u306e\u89e3\u6c7a\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u60aa\u3044\u4f8b\uff08SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u306e\u5371\u967a\u3042\u308a\uff09\n$query-&gt;whereRaw(\"name LIKE '%$keyword%'\");\n\n\/\/ \u826f\u3044\u4f8b\uff08\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u3092\u4f7f\u7528\uff09\n$query-&gt;where('name', 'like', \"%{$keyword}%\");\n\n\/\/ \u3088\u308a\u5b89\u5168\u306a\u5b9f\u88c5\n$query-&gt;where('name', 'like', '%' . str_replace(['%', '_'], ['\\%', '\\_'], $keyword) . '%');<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>N+1\u554f\u984c\u306e\u56de\u907f<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u554f\u984c\u306e\u3042\u308b\u5b9f\u88c5\n$products = Product::search($keyword)-&gt;get();\nforeach ($products as $product) {\n    echo $product-&gt;category-&gt;name; \/\/ N+1\u554f\u984c\u767a\u751f\n}\n\n\/\/ \u6539\u5584\u3055\u308c\u305f\u5b9f\u88c5\n$products = Product::search($keyword)\n    -&gt;with('category')  \/\/ Eager Loading\n    -&gt;get();<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30e1\u30e2\u30ea\u4f7f\u7528\u91cf\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30e1\u30e2\u30ea\u3092\u5927\u91cf\u306b\u4f7f\u7528\u3059\u308b\u5b9f\u88c5\n$products = Product::all()-&gt;filter(function($product) use ($keyword) {\n    return str_contains($product-&gt;name, $keyword);\n});\n\n\/\/ \u6700\u9069\u5316\u3055\u308c\u305f\u5b9f\u88c5\n$products = Product::query()\n    -&gt;where('name', 'like', \"%{$keyword}%\")\n    -&gt;cursor()  \/\/ \u30e1\u30e2\u30ea\u52b9\u7387\u306e\u826f\u3044\u30a4\u30c6\u30ec\u30fc\u30b7\u30e7\u30f3\n    -&gt;filter(function($product) {\n        return $product-&gt;isAvailable();\n    });<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-22\">\u5c06\u6765\u306e\u6a5f\u80fd\u62e1\u5f35\u306b\u5099\u3048\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08\u306e\u30dd\u30a4\u30f3\u30c8<\/h3>\n\n\n\n<p>\u4fdd\u5b88\u6027\u3068\u62e1\u5f35\u6027\u3092\u8003\u616e\u3057\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08\u306e\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u691c\u7d22\u6761\u4ef6\u306e\u30ab\u30d7\u30bb\u30eb\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/SearchFilters\/ProductSearchFilter.php\nclass ProductSearchFilter\n{\n    protected $query;\n    protected $filters;\n\n    public function __construct($query, array $filters)\n    {\n        $this-&gt;query = $query;\n        $this-&gt;filters = $filters;\n    }\n\n    public function apply()\n    {\n        foreach ($this-&gt;filters as $filter =&gt; $value) {\n            if (method_exists($this, $filter)) {\n                $this-&gt;$filter($value);\n            }\n        }\n        return $this-&gt;query;\n    }\n\n    protected function keyword($value)\n    {\n        return $this-&gt;query-&gt;where('name', 'like', \"%{$value}%\");\n    }\n\n    protected function priceRange($value)\n    {\n        return $this-&gt;query-&gt;whereBetween('price', [$value['min'], $value['max']]);\n    }\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u691c\u7d22\u7d50\u679c\u306e\u5909\u63db\u51e6\u7406\u306e\u5206\u96e2<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Transformers\/ProductTransformer.php\nclass ProductTransformer\n{\n    public function transform(Product $product)\n    {\n        return [\n            'id' =&gt; $product-&gt;id,\n            'name' =&gt; $product-&gt;name,\n            'price' =&gt; $this-&gt;formatPrice($product-&gt;price),\n            'category' =&gt; $product-&gt;category?-&gt;name,\n            'availability' =&gt; $this-&gt;getAvailabilityStatus($product)\n        ];\n    }\n\n    protected function formatPrice($price)\n    {\n        return number_format($price) . '\u5186';\n    }\n\n    protected function getAvailabilityStatus(Product $product)\n    {\n        return $product-&gt;stock &gt; 0 ? '\u5728\u5eab\u3042\u308a' : '\u5728\u5eab\u306a\u3057';\n    }\n}<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u691c\u7d22\u30ed\u30b0\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Observers\/SearchLogObserver.php\nclass SearchLogObserver\n{\n    public function created(SearchHistory $searchHistory)\n    {\n        Log::channel('search')-&gt;info('Search performed', [\n            'user_id' =&gt; $searchHistory-&gt;user_id,\n            'keyword' =&gt; $searchHistory-&gt;keyword,\n            'filters' =&gt; $searchHistory-&gt;filters,\n            'results' =&gt; $searchHistory-&gt;result_count\n        ]);\n    }\n}<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u88c5\u306b\u3088\u3063\u3066\u5f97\u3089\u308c\u308b\u5229\u70b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c6\u30b9\u30c8\u306e\u4fe1\u983c\u6027<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u7db2\u7f85\u7684\u306a\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9<\/li>\n\n\n\n<li>\u30a8\u30c3\u30b8\u30b1\u30fc\u30b9\u306e\u8003\u616e<\/li>\n\n\n\n<li>\u81ea\u52d5\u5316\u3055\u308c\u305f\u30c6\u30b9\u30c8\u5b9f\u884c<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d0\u30b0\u306e\u65e9\u671f\u767a\u898b\u3068\u5bfe\u51e6<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u4e00\u822c\u7684\u306a\u554f\u984c\u3078\u306e\u5bfe\u7b56<\/li>\n\n\n\n<li>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u554f\u984c\u306e\u89e3\u6c7a<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ea\u30b9\u30af\u306e\u8efd\u6e1b<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u3068\u62e1\u5f35\u6027<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8cac\u52d9\u306e\u660e\u78ba\u306a\u5206\u96e2<\/li>\n\n\n\n<li>\u518d\u5229\u7528\u53ef\u80fd\u306a\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8<\/li>\n\n\n\n<li>\u5c06\u6765\u306e\u6a5f\u80fd\u8ffd\u52a0\u3078\u306e\u5bfe\u5fdc<\/li>\n<\/ul>\n\n\n\n<p>\u6b21\u7ae0\u3067\u306f\u3001\u691c\u7d22\u6a5f\u80fd\u3092\u3055\u3089\u306b\u5f37\u5316\u3059\u308b\u305f\u3081\u306e\u5916\u90e8\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u6d3b\u7528\u65b9\u6cd5\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-23\">Laravel \u306e\u691c\u7d22\u6a5f\u80fd\u3092\u5f37\u5316\u3059\u308b\u5916\u90e8\u30d1\u30c3\u30b1\u30fc\u30b8<\/h2>\n\n\n\n<p>\u30c7\u30fc\u30bf\u91cf\u304c\u5897\u52a0\u3057\u305f\u308a\u3001\u3088\u308a\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u304c\u5fc5\u8981\u306b\u306a\u3063\u305f\u5834\u5408\u3001\u5916\u90e8\u30d1\u30c3\u30b1\u30fc\u30b8\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u691c\u7d22\u6a5f\u80fd\u3092\u5927\u5e45\u306b\u5f37\u5316\u3067\u304d\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u3001Laravel Scout\u306e\u5c0e\u5165\u65b9\u6cd5\u3068Elasticsearch\u3068\u306e\u9023\u643a\u65b9\u6cd5\u3001\u305d\u3057\u3066\u4ed6\u306e\u6709\u7528\u306a\u30d1\u30c3\u30b1\u30fc\u30b8\u306b\u3064\u3044\u3066\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-24\">Scout \u5c0e\u5165\u306b\u3088\u308b\u5168\u6587\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p>Laravel Scout\u3092\u4f7f\u7528\u3057\u305f\u5168\u6587\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Scout\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\ncomposer require laravel\/scout\n\n# \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u516c\u958b\nphp artisan vendor:publish --provider=\"Laravel\\Scout\\ScoutServiceProvider\"\n\n# Meilisearch\u30c9\u30e9\u30a4\u30d0\u30fc\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\uff08\u9078\u629e\u53ef\u80fd\uff09\ncomposer require meilisearch\/meilisearch-php http-interop\/http-factory-guzzle<\/pre>\n\n\n\n<p>\u30e2\u30c7\u30eb\u3078\u306eScout\u5b9f\u88c5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Models\/Product.php\nuse Laravel\\Scout\\Searchable;\n\nclass Product extends Model\n{\n    use Searchable;\n\n    \/**\n     * \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306b\u542b\u3081\u308b\u30c7\u30fc\u30bf\u306e\u5b9a\u7fa9\n     *\/\n    public function toSearchableArray()\n    {\n        return [\n            'id' =&gt; $this-&gt;id,\n            'name' =&gt; $this-&gt;name,\n            'description' =&gt; $this-&gt;description,\n            'category_name' =&gt; $this-&gt;category-&gt;name,\n            'price' =&gt; $this-&gt;price,\n            'tags' =&gt; $this-&gt;tags-&gt;pluck('name')-&gt;join(' ')\n        ];\n    }\n\n    \/**\n     * \u691c\u7d22\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\n     *\/\n    public function searchableAs()\n    {\n        return 'products_index';\n    }\n}<\/pre>\n\n\n\n<p>Scout \u3092\u4f7f\u7528\u3057\u305f\u691c\u7d22\u306e\u5b9f\u88c5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/Http\/Controllers\/ProductController.php\npublic function scoutSearch(Request $request)\n{\n    $results = Product::search($request-&gt;input('query'))\n        -&gt;within('products_index')\n        -&gt;withTrashed() \/\/ \u524a\u9664\u6e08\u307f\u3082\u542b\u3081\u308b\u5834\u5408\n        -&gt;get();\n\n    return view('products.search', compact('results'));\n}\n\n\/\/ \u3088\u308a\u9ad8\u5ea6\u306a\u691c\u7d22\u306e\u5b9f\u88c5\u4f8b\npublic function advancedScoutSearch(Request $request)\n{\n    $query = $request-&gt;input('query');\n    $categories = $request-&gt;input('categories', []);\n    $priceRange = $request-&gt;input('price_range');\n\n    $results = Product::search($query, function ($meilisearch, $query, $options) use ($categories, $priceRange) {\n        \/\/ \u30d5\u30a3\u30eb\u30bf\u30fc\u306e\u8ffd\u52a0\n        $filters = [];\n\n        if (!empty($categories)) {\n            $filters[] = 'category_id IN [' . implode(',', $categories) . ']';\n        }\n\n        if ($priceRange) {\n            $filters[] = \"price &gt;= {$priceRange['min']} AND price &lt;= {$priceRange['max']}\";\n        }\n\n        if (!empty($filters)) {\n            $options['filter'] = implode(' AND ', $filters);\n        }\n\n        return $meilisearch-&gt;search($query, $options);\n    })\n    -&gt;within('products_index')\n    -&gt;paginate();\n\n    return view('products.search', compact('results'));\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-25\">Elasticsearch \u3068\u306e\u9023\u643a\u624b\u9806<\/h3>\n\n\n\n<p>Elasticsearch\u3092\u4f7f\u7528\u3057\u305f\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd\u306e\u5b9f\u88c5\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Elasticsearch\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\ncomposer require elasticsearch\/elasticsearch\n\n# Scout Elasticsearch\u30c9\u30e9\u30a4\u30d0\u30fc\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\ncomposer require babenkoivan\/scout-elasticsearch-driver<\/pre>\n\n\n\n<p>Elasticsearch\u306e\u8a2d\u5b9a\u3068\u5b9f\u88c5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ config\/elasticsearch.php\nreturn [\n    'hosts' =&gt; [\n        env('ELASTICSEARCH_HOST', 'localhost:9200'),\n    ],\n    'indices' =&gt; [\n        'products' =&gt; [\n            'mappings' =&gt; [\n                'properties' =&gt; [\n                    'name' =&gt; [\n                        'type' =&gt; 'text',\n                        'analyzer' =&gt; 'kuromoji'  \/\/ \u65e5\u672c\u8a9e\u5f62\u614b\u7d20\u89e3\u6790\n                    ],\n                    'description' =&gt; [\n                        'type' =&gt; 'text',\n                        'analyzer' =&gt; 'kuromoji'\n                    ],\n                    'price' =&gt; [\n                        'type' =&gt; 'integer'\n                    ],\n                    'category_id' =&gt; [\n                        'type' =&gt; 'integer'\n                    ]\n                ]\n            ]\n        ]\n    ]\n];\n\n\/\/ app\/SearchRules\/ProductSearchRule.php\nuse ScoutElastic\\SearchRule;\n\nclass ProductSearchRule extends SearchRule\n{\n    public function buildHighlightPayload()\n    {\n        return [\n            'fields' =&gt; [\n                'name' =&gt; [\n                    'type' =&gt; 'plain'\n                ],\n                'description' =&gt; [\n                    'type' =&gt; 'plain'\n                ]\n            ]\n        ];\n    }\n\n    public function buildQueryPayload()\n    {\n        return [\n            'must' =&gt; [\n                'multi_match' =&gt; [\n                    'query' =&gt; $this-&gt;query,\n                    'fields' =&gt; ['name^3', 'description'],\n                    'fuzziness' =&gt; 'AUTO'\n                ]\n            ],\n            'filter' =&gt; [\n                'range' =&gt; [\n                    'price' =&gt; [\n                        'gte' =&gt; $this-&gt;filters['price_min'] ?? null,\n                        'lte' =&gt; $this-&gt;filters['price_max'] ?? null\n                    ]\n                ]\n            ]\n        ];\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-26\">\u304a\u3059\u3059\u3081\u306e\u691c\u7d22\u95a2\u9023\u30d1\u30c3\u30b1\u30fc\u30b8\u3068\u9078\u5b9a\u57fa\u6e96<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5168\u6587\u691c\u7d22\u30a8\u30f3\u30b8\u30f3<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Laravel Scout + Meilisearch\n<ul class=\"wp-block-list\">\n<li>\u9ad8\u901f\u3067\u5c0e\u5165\u304c\u5bb9\u6613<\/li>\n\n\n\n<li>\u65e5\u672c\u8a9e\u5bfe\u5fdc\u304c\u53ef\u80fd<\/li>\n\n\n\n<li>\u5c0f\u301c\u4e2d\u898f\u6a21\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u6700\u9069<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Elasticsearch\n<ul class=\"wp-block-list\">\n<li>\u5927\u898f\u6a21\u30c7\u30fc\u30bf\u306b\u5f37\u3044<\/li>\n\n\n\n<li>\u9ad8\u5ea6\u306a\u691c\u7d22\u6a5f\u80fd<\/li>\n\n\n\n<li>\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u6027\u304c\u9ad8\u3044<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u691c\u7d22UI\u95a2\u9023<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Laravel Livewire <code>\/\/ app\/Http\/Livewire\/ProductSearch.php class ProductSearch extends Component { public $query = ''; public $products = []; public function search() { $this-&amp;gt;products = Product::search($this-&amp;gt;query)-&amp;gt;get(); } public function render() { return view('livewire.product-search'); } }<\/code><\/li>\n\n\n\n<li>Vue.js + Algolia<br><code>javascript \/\/ resources\/js\/components\/ProductSearch.vue &lt;template&gt; &lt;ais-instant-search :search-client=\"searchClient\" index-name=\"products\" &gt; &lt;ais-search-box \/&gt; &lt;ais-hits&gt; &lt;template slot=\"item\" slot-scope=\"{ item }\"&gt; &lt;product-card :product=\"item\" \/&gt; &lt;\/template&gt; &lt;\/ais-hits&gt; &lt;\/ais-instant-search&gt; &lt;\/template&gt;<\/code><\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30ad\u30e3\u30c3\u30b7\u30e5\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Laravel Cache<\/li>\n\n\n\n<li>Redis Cache<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u4f7f\u7528\u3057\u305f\u691c\u7d22\u7d50\u679c\u306e\u6700\u9069\u5316\n   public function search($query)\n   {\n       $cacheKey = 'search_' . md5($query);\n\n       return Cache::remember($cacheKey, now()-&gt;addHours(1), function () use ($query) {\n           return Product::search($query)-&gt;get();\n       });\n   }<\/pre>\n\n\n\n<p>\u30d1\u30c3\u30b1\u30fc\u30b8\u9078\u5b9a\u306e\u57fa\u6e96\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u898f\u6a21<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c7\u30fc\u30bf\u91cf<\/li>\n\n\n\n<li>\u30e6\u30fc\u30b6\u30fc\u6570<\/li>\n\n\n\n<li>\u691c\u7d22\u983b\u5ea6<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5fc5\u8981\u306a\u6a5f\u80fd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5168\u6587\u691c\u7d22<\/li>\n\n\n\n<li>\u30d5\u30a1\u30bb\u30c3\u30c8\u691c\u7d22<\/li>\n\n\n\n<li>\u5730\u7406\u7a7a\u9593\u691c\u7d22<\/li>\n\n\n\n<li>\u65e5\u672c\u8a9e\u5bfe\u5fdc<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u904b\u7528\u30b3\u30b9\u30c8<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5c0e\u5165\u306e\u5bb9\u6613\u3055<\/li>\n\n\n\n<li>\u4fdd\u5b88\u306e\u624b\u9593<\/li>\n\n\n\n<li>\u30a4\u30f3\u30d5\u30e9\u30b3\u30b9\u30c8<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u8981\u4ef6<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u691c\u7d22\u901f\u5ea6<\/li>\n\n\n\n<li>\u30b9\u30b1\u30fc\u30e9\u30d3\u30ea\u30c6\u30a3<\/li>\n\n\n\n<li>\u30ea\u30bd\u30fc\u30b9\u4f7f\u7528\u91cf<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30d1\u30c3\u30b1\u30fc\u30b8\u3092\u9069\u5207\u306b\u9078\u629e\u30fb\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8981\u4ef6\u306b\u6700\u9069\u306a\u691c\u7d22\u6a5f\u80fd\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/ &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33,12],"tags":[],"class_list":{"0":"post-3285","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-php-laravel","7":"category-php","8":"nothumb"},"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3285"}],"version-history":[{"count":2,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3285\/revisions"}],"predecessor-version":[{"id":3287,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3285\/revisions\/3287"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}