{"id":3194,"date":"2026-08-28T13:15:34","date_gmt":"2026-08-28T04:15:34","guid":{"rendered":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/?page_id=3194"},"modified":"2026-09-24T13:37:20","modified_gmt":"2026-09-24T04:37:20","slug":"laravel-07","status":"publish","type":"page","link":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/programming\/php\/laravel-07","title":{"rendered":"\u8a8d\u53ef\u3068\u30a2\u30af\u30bb\u30b9\u5236\u5fa1"},"content":{"rendered":"<details>\n  <summary>\n    \u524d\u56de\u7d42\u4e86\u6642\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\n  <\/summary>\n  <p>Laravel\u3092\u4f7f\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u3057\u3066\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n<div class='console'><pre>\n$ git clone https:\/\/kiku3.tsbio.info\/git\/study-laravel.git study_laravel\n<\/pre><\/div>\n\n<p>\u3053\u306e\u7ae0\u958b\u59cb\u6642\u70b9\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306f chapt7 \u30d6\u30e9\u30f3\u30c1\u306b\u3042\u308a\u307e\u3059\u3002<\/p>\n<div class='console'><pre>\n$ git switch chapt7\n<\/pre><\/div>\n\n<p>\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u81ea\u5206\u3067\u66f8\u3044\u3066\u3044\u304f\u5834\u5408\u306f\u3001\u81ea\u5206\u7528\u306e\u30d6\u30e9\u30f3\u30c1\u3092\u3064\u304f\u308b\u3068\u3088\u3044\u3067\u3059\u3002<\/p>\n<div class='console'><pre>\n$ git switch -c my7 chapt7\n<\/pre><\/div>\n\n<p>Laravel\u306e\u30b3\u30fc\u30c9\u306fsrc\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304b\u3089\u306e\u76f8\u5bfe\u30d1\u30b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n\n<h3>\u30a8\u30e9\u30fc\u3078\u306e\u5bfe\u51e6<\/h3>\n<ul>\n  <li>\n    <h4>Laravel\u306e\u30d1\u30c3\u30b1\u30fc\u30b8\u304c\u306a\u3044<\/h4>\n    <p>composer install \u3092\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u958b\u767a\u6bb5\u968e\u306b\u5fdc\u3058\u3066\u4e0d\u8db3\u3059\u308b\u30d1\u30c3\u30b1\u30fc\u30b8\u304c\u3042\u308b\u3068\u304d\u306f\u3001\u518d\u5ea6 composer install \u304c\u5fc5\u8981\u306a\u5834\u5408\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n  <\/li>\n  <li>\n    <h4>\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u304c\u6b63\u3057\u304f\u306a\u3044<\/h4>\n    <p>tempnam()\u304c\u5b9f\u884c\u3067\u304d\u306a\u3044\u306a\u3069\u306e\u30a8\u30e9\u30fc\u304c\u51fa\u308b\u3068\u304d\u306f\u3001storage\u3068bootstrap\/cache\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u6240\u6709\u8005\u3068\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044(\u7b2c1\u7ae0\u3092\u53c2\u7167)<\/p>\n  <\/li>\n  <li>\n    <h4>Vite manifest not found <\/h4>\n    <p>\u958b\u767a\u4e2d\u306a\u3089 npm run dev\u3001\u672c\u756a\u74b0\u5883\u306a\u3089 npm run build\u3092\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n  <\/li>\n  <li>\n    <h4>npm run dev\u304c\u52d5\u304b\u306a\u3044<\/h4>\n    <p>npm install \u3092\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n  <\/li>\n<\/ul>\n<\/details>\n\n\n<h2>\u8a8d\u53ef (Authorization) \u3068\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h2>\n<p>\u524d\u7ae0\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u306e\u8a8d\u8a3c (authentication) \u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3057\u305f\u3002\n\u6b21\u306f\u3069\u306e\u30e6\u30fc\u30b6\u30fc\u306f\u4f55\u304c\u3067\u304d\u308b\u306e\u304b\u3092\u8a8d\u53ef (authorization) \u3059\u308b\u3057\u304f\u307f\u3092\u3064\u304f\u308a\u307e\u3059\u3002\nLaravel\u3067\u306f\u5f79\u5272 (role) \u3068\u6a29\u9650 (permission) \u3067\u30e6\u30fc\u30b6\u30fc\u306e\u30a2\u30af\u30bb\u30b9\u3092\u5236\u5fa1\u3057\u307e\u3059\u3002<\/p>\n<p>\u6a29\u9650\u306f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u6a5f\u80fd(\u4e3b\u306b\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30c6\u30fc\u30d6\u30eb\u306b\u5bfe\u3059\u308b\u64cd\u4f5c)\u306b\u5bfe\u3057\u3066\u8a2d\u5b9a\u3057\u307e\u3059\u3002\noligo\u30c6\u30fc\u30d6\u30eb\u306b\u5bfe\u3057\u3066\u3001select\u3067\u304d\u308b\u6a29\u9650\u3001insert\u3067\u304d\u308b\u6a29\u9650\u3001\u3068\u3044\u3046\u3088\u3046\u611f\u3058\u3067\u3059\u3002\n\u4f8b\u3048\u3070select\u3067\u3042\u308c\u3070\u3001<code>Oligo::all()<\/code> \u3068\u3044\u3046\u5f62\u3067\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u4e2d\u306b\u73fe\u308c\u308b\u306e\u3067\u3001\u3053\u306e\u90e8\u5206\u3092\u5b9f\u884c\u3067\u304d\u308b\u304b\u3069\u3046\u304b\u3068\u3044\u3046\u3088\u3046\u306b\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<p>oligo\u30c6\u30fc\u30d6\u30eb\u306b\u5bfe\u3057\u3066select\u3067\u304d\u308b\u6a29\u9650\u3092oligo.read\u3068\u540d\u4ed8\u3051\u305f\u3068\u3057\u307e\u3059\u3002\n\u3053\u306e\u540d\u79f0\u81ea\u4f53\u304c\u306a\u306b\u304b\u306e\u52b9\u679c\u3092\u6301\u3064\u3082\u306e\u3067\u306f\u306a\u3044\u3053\u3068\u306b\u6ce8\u610f\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n\u6a29\u9650\u540d\u3092\u30d7\u30ed\u30b0\u30e9\u30e0\u306b\u95a2\u9023\u4ed8\u3051\u308b\u306e\u306f\u30d7\u30ed\u30b0\u30e9\u30de\u30fc\u306e\u8cac\u4efb\u3067\u3059\u3002\n<code>Oligo::all()<\/code>\u304c\u3042\u308b\u306e\u306fOligoController\u306eindex\u30e1\u30bd\u30c3\u30c9\u3067\u3059\u3002\noligo.read\u306e\u6a29\u9650\u3092\u3082\u3064\u30e6\u30fc\u30b6\u30fc\u306b\u306e\u307f <code>Oligo::all()<\/code> \u3092\u5b9f\u884c\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u305f\u3081\u306b\u3001<code>if($user-&gt;can('oligo.read')) Oligo::all();<\/code> \u3068\u3044\u3046\u3088\u3046\u306b\u30b3\u30fc\u30c9\u3092\u66f8\u304d\u307e\u3059\u3002\n\u8a8d\u53ef\u306f\u3001<strong>\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u3067\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u30e1\u30bd\u30c3\u30c9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u3092\u5236\u5fa1\u3059\u308b\u65b9\u6cd5<\/strong>\u3001<strong>\u30e1\u30bd\u30c3\u30c9\u5185\u3067\u30b3\u30fc\u30c9\u306e\u5b9f\u884c\u3092\u5236\u5fa1\u3059\u308b\u65b9\u6cd5<\/strong>\u3001<strong>\u30d3\u30e5\u30fc\u3067\u8868\u793a\u3092\u5236\u5fa1\u3059\u308b\u65b9\u6cd5<\/strong>\u3001\u306a\u3069\u3067\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>\u30e6\u30fc\u30b6\u30fc\u3054\u3068\u306b\u6a29\u9650\u3092\u8a2d\u5b9a\u3057\u3066\u3044\u304f\u306e\u306f\u5927\u5909\u306a\u306e\u3067\u3001\u3044\u304f\u3064\u304b\u306e\u6a29\u9650\u3092\u30bb\u30c3\u30c8\u306b\u3057\u3066\u5f79\u5272 (role) \u3068\u3057\u307e\u3059\u3002\n\u3053\u306e\u5f79\u5272\u3092\u30e6\u30fc\u30b6\u30fc\u306b\u308f\u308a\u3042\u3066\u308b\u3053\u3068\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u3068\u6a29\u9650\u304c\u7d50\u3073\u4ed8\u3051\u3089\u308c\u3001\u6a29\u9650\u306e\u6709\u7121\u3092\u5224\u5b9a\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<p>spatie\/laravel-permission\u3068\u3044\u3046\u30d1\u30c3\u30b1\u30fc\u30b8\u306f permissions\u3001roles\u306a\u3069\u306e\u30c6\u30fc\u30d6\u30eb\u3092\u3064\u304f\u308a\u3001users\u3068\u7d50\u5408\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<h3>spatie\/laravel-permission\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b<\/h3>\n<p>spatie\/laravel-permission\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059\u3002\n\u7d9a\u3044\u3066\u30c6\u30fc\u30d6\u30eb\u3092\u4f5c\u6210\u3057\u307e\u3059 (migrate)\u3002<\/p>\n<div class='console'><pre>\n# composer require spatie\/laravel-permission\n# artisan vendor:publish --provider=\"Spatie\\Permission\\PermissionServiceProvider\"\n# .\/artizan migrate\n<\/pre><\/div>\n<h3>\u30e6\u30fc\u30b6\u30fc\u30e2\u30c7\u30eb\u306e\u4fee\u6b63<\/h3>\n<p>Spatie\u304c\u63d0\u4f9b\u3059\u308b\u6a29\u9650\u306e\u78ba\u8a8d\u306e\u305f\u3081\u306e\u30e1\u30bd\u30c3\u30c9\u3092Model\/User\u306b\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Models\/User.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Models;\n \n\/\/ use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Database\\Factories\\UserFactory;\nuse Illuminate\\Database\\Eloquent\\Attributes\\Fillable;\nuse Illuminate\\Database\\Eloquent\\Attributes\\Hidden;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Spatie\\Permission\\Traits\\HasRoles;  \/\/ \u8a8d\u53ef\u306b\u95a2\u3059\u308b\u30e1\u30bd\u30c3\u30c9\u304c\u4f7f\u3048\u308b\u3088\u3046\u306b\u306a\u308b\n \n#[Fillable([&#039;name&#039;, &#039;email&#039;, &#039;password&#039;])]\n#[Hidden([&#039;password&#039;, &#039;remember_token&#039;])]\nclass User extends Authenticatable\n{\n    \/** @use HasFactory&lt;UserFactory&gt; *\/\n    use HasFactory, Notifiable, HasRoles; \/\/ HasRoles\u3092\u8ffd\u52a0\n \n    \/**\n     * Get the attributes that should be cast.\n     *\n     * @return array&lt;string, string&gt;\n     *\/\n    protected function casts(): array\n    {\n        return [\n            &#039;email_verified_at&#039; =&gt; &#039;datetime&#039;,\n            &#039;password&#039; =&gt; &#039;hashed&#039;,\n        ];\n    }\n}\n<\/pre>\n<\/div>\n<h3>\u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u3092\u767b\u9332<\/h3>\n<p>tinker\u3067\u8a66\u3057\u307e\u3059\u3002<\/p>\n<div class='console'><pre>\n# .\/artisan tinker\n> use Spatie\\Permission\\Models\\Permission\n> $ow = Permission::create(['name' => 'oligo.write'])  # oligo.write\u3068\u3044\u3046\u6a29\u9650\u3092\u8ffd\u52a0\n= Spatie\\Permission\\Models\\Permission {#294\n  guard_name: \"web\",\n  name: \"oligo.write\",\n  updated_at: \"2026-08-28 01:48:37\",\n  created_at: \"2026-08-28 01:48:37\",\n  id: 25,\n}\n> $or = Permission::create(['name' => 'oligo.read']) # oligo.read\u3068\u3044\u3046\u6a29\u9650\u3092\u8ffd\u52a0\n= Spatie\\Permission\\Models\\Permission {#7546\n  guard_name: \"web\",\n  name: \"oligo.read\",\n  updated_at: \"2026-08-28 01:48:48\",\n  created_at: \"2026-08-28 01:48:48\",\n  id: 26,\n}\n> use Spatie\\Permission\\Models\\Role\n> $role = Role::create(['name' => 'oligo.user']) # oligo.user\u3068\u3044\u3046\u5f79\u5272\u3092\u8ffd\u52a0\n= Spatie\\Permission\\Models\\Role {#8044\n  guard_name: \"web\",\n  name: \"oligo.user\",\n  updated_at: \"2026-08-28 01:49:36\",\n  created_at: \"2026-08-28 01:49:36\",\n  id: 2,\n}\n> $role->syncPermissions($or)  # oligo.user\u306boligo.read\u3092\u4ed8\u4e0e\n= Spatie\\Permission\\Models\\Role {#8044\n  guard_name: \"web\",\n  name: \"oligo.user\",\n  updated_at: \"2026-08-28 01:49:36\",\n  created_at: \"2026-08-28 01:49:36\",\n  id: 2,\n}\n> use App\\Models\\User\n> $user = User::first()\n= App\\Models\\User {#8891\n  id: 2,\n  name: \"test user\",\n  email: \"test@example.com\",\n  email_verified_at: null,\n  #password: \"\\$2yxxx\",\n  #remember_token: null,\n  created_at: \"2026-08-26 02:14:30\",\n  updated_at: \"2026-08-26 02:14:30\",\n}\n> $user->syncRoles($role)  # test user\u306boligo.user\u3068\u3044\u3046\u5f79\u5272\u3092\u4ed8\u4e0e\n> $user->can('oligo.read') # test user\u306foligo.read\u6a29\u9650\u3092\u6301\u3064\u304b? -> true\n= true\n>\u3000$user->can('oligo.write') # test user\u306foligo.write\u6a29\u9650\u3092\u6301\u3064\u304b? -> false\n= false\n<\/pre><\/div>\n<h2>\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h2>\n<h3>\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u6bb5\u968e\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h3>\n<p>\u30df\u30c9\u30eb\u30a6\u30a7\u30a2\u306b can:oligo.read \u3092\u8ffd\u52a0\u3059\u308b\u3002\noligo.write\u306b\u3059\u308b\u3068\u30a2\u30af\u30bb\u30b9\u3067\u304d\u306a\u304f\u306a\u308b\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">routes\/oligo.php<\/h5>\n<pre >\n&lt;?php\n \nuse Illuminate\\Support\\Facades\\Route;\nuse App\\Http\\Controllers\\OligoController;\n \n\/\/ \u30aa\u30ea\u30b4DNA\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\nRoute::middleware([&#039;auth&#039;, &#039;verified&#039;, &#039;auto.login:test user&#039;, &#039;can:oligo.read&#039;])\n    \/* can\u306fAuthorize\u30df\u30c9\u30eb\u30a6\u30a7\u30a2\u306e\u5225\u540d\u3068\u3057\u3066\u767b\u9332\u3055\u308c\u3066\u3044\u308b\n     * oligo.read\u3092oligo.write\u306b\u5909\u3048\u308b\u3068 \/oligo \u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u306a\u304f\u306a\u308b\n     *\/\n    -&gt;prefix(&#039;oligo&#039;)\n    -&gt;as(&#039;web.oligo.&#039;)\n    -&gt;group(function (){\n        Route::get(&#039;\/&#039;, [OligoController::class, &#039;index&#039;])-&gt;name(&#039;index&#039;);\n        Route::get(&#039;search&#039;, [OligoController::class, &#039;search&#039;])-&gt;name(&#039;search&#039;);\n        Route::get(&#039;create&#039;, [OligoController::class, &#039;create&#039;])-&gt;name(&#039;create&#039;);\n        Route::post(&#039;\/&#039;, [OligoController::class, &#039;store&#039;])-&gt;name(&#039;store&#039;);\n \n        \/\/ \u7de8\u96c6\u30d5\u30a9\u30fc\u30e0\u3068\u30c7\u30fc\u30bf\u66f4\u65b0\n        Route::get(&#039;edit&#039;, [OligoController::class, &#039;edit&#039;])-&gt;name(&#039;edit&#039;);\n        Route::put(&#039;\/{item}&#039;, [OligoController::class, &#039;update&#039;])-&gt;name(&#039;update&#039;);\n    });\n<\/pre>\n<\/div>\n<h3>\u30c7\u30fc\u30bf\u53d6\u5f97\u6bb5\u968e\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h3>\n<p>Request\u304b\u3089User\u3092\u53d6\u5f97\u3057\u3066\u3001can\u3092\u4f7f\u3046\u3002\n\u307e\u305f\u306f Gate\u306eauthorize\u30e1\u30bd\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u308b\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Http\/Controllers\/OligoController.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Http\\Controllers;\n \nuse App\\Models\\Oligo;\nuse App\\Services\\OligoService;\nuse App\\Http\\Requests\\OligoRequest;\nuse App\\Http\\Requests\\OligoSearchRequest;\nuse App\\Http\\Requests\\OligosRequest;\n \nclass OligoController\n{\n    public function __construct(\n        private OligoService $service\n    ) {\n    }\n \n    public function index(){\n \n        \/*\n         * oligo.read\u6a29\u9650\u304c\u4ed8\u4e0e\u3055\u308c\u3066\u3044\u308c\u3070\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3067\u304d\u308b\u3002\n         *\/\n        if(request()-&gt;user()-&gt;can(&#039;oligo.read&#039;)){\n            $items = Oligo::all();\n        }else{\n            $items = [];\n        }\n \n        return view(&#039;oligo.index&#039;, compact(&#039;items&#039;))\n            -&gt;fragmentIf(request()-&gt;hasHeader(&#039;HX-Request&#039;), &quot;feature-oligo-index&quot;)\n        ;\n    }\n \n    public function create(){\n        return view(&#039;oligo.create&#039;)\n            -&gt;fragmentIf(request()-&gt;hasHeader(&#039;HX-Request&#039;), &quot;feature-oligo-create&quot;)\n        ;\n    }\n \n    public function store(OligosRequest $request){\n \n        \/*\n         * oligo.write\u6a29\u9650\u304c\u306a\u3051\u308c\u3070HTTP \u30ec\u30b9\u30dd\u30f3\u30b9 403\u3092\u51fa\u3057\u3066\u7d42\u4e86\u3059\u308b\n         *\/\n        \\Illuminate\\Support\\Facades\\Gate::authorize(&#039;oligo.write&#039;);\n        \n        try{\n            $oligos = $request-&gt;validOligos;\n            $data = $this-&gt;service-&gt;create($oligos);\n \n            return response()-&gt;json(array_merge($data, [\n                &#039;status&#039; =&gt; &#039;success&#039;, \n                &#039;input&#039; =&gt; $oligos,\n            ]), 200);\n        }catch(\\Throwable $e){\n            return response()-&gt;json([&#039;status&#039; =&gt; &#039;error&#039;, &#039;message&#039; =&gt; $e-&gt;getMessage()], 400);\n        }\n    }\n \n    \/\/ \u691c\u7d22\n    public function search(OligoSearchRequest $request)\n    {\n        try{\n            $query = $request-&gt;validated();\n\t    $query[&#039;use_regex&#039;] = $query[&#039;use_regex&#039;] ?? false;\n            return response()-&gt;json([\n                &#039;status&#039; =&gt; &#039;success&#039;,\n                &#039;data&#039; =&gt; $this-&gt;service-&gt;search($query),\n            ], 200);\n \n        }catch(\\Throwable $e){\n            return response()-&gt;json([&#039;status&#039; =&gt; &#039;error&#039;, &#039;message&#039; =&gt; $e-&gt;getMessage()], 400);\n        }\n    }\n \n    public function edit(){\n        return view(&#039;oligo.edit&#039;)\n            -&gt;fragmentIf(request()-&gt;hasHeader(&#039;HX-Request&#039;), &quot;feature-oligo-edit&quot;)\n        ;\n    }\n \n    public function update(OligoRequest $request, Oligo $item){\n        try{\n            $item-&gt;update($request-&gt;validated());\n \n            return response()-&gt;json([\n                &#039;status&#039; =&gt; &#039;success&#039;, \n                &#039;item&#039; =&gt; $item,\n            ], 200);\n        }catch(\\Throwable $e){\n            return response()-&gt;json([&#039;status&#039; =&gt; &#039;error&#039;, &#039;message&#039; =&gt; $e-&gt;getMessage()], 400);\n        }\n    }\n}\n<\/pre>\n<\/div>\n<h3>\u30d3\u30e5\u30fc\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h3>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">resources\/views\/oligo\/module.blade.php<\/h5>\n<pre >\n@extends(&#039;layouts.app&#039;)\n \n@section(&#039;module&#039;)\n  @php($module = &#039;oligo&#039;)  {{-- \u30e2\u30b8\u30e5\u30fc\u30eb\u540d\u3092\u5909\u6570\u306b\u8a2d\u5b9a --}}\n  &lt;x-module id=&#039;{{ $module }}&#039;&gt;\n    &lt;!-- \u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u30e1\u30cb\u30e5\u30fc --&gt;\n    &lt;nav&gt;\n      &lt;ul class=&#039;feature-tabs&#039; role=&#039;tablist&#039;&gt;\n        @foreach([\n          {{-- \u30d5\u30a3\u30fc\u30c1\u30e3\u30fc\u3054\u3068\u306e\u8a2d\u5b9a --}}\n          &#039;index&#039; =&gt; [&#039;label&#039; =&gt; &#039;\u4e00\u89a7&#039;, &#039;permission&#039; =&gt; &#039;read&#039;],\n          &#039;create&#039; =&gt; [&#039;label&#039; =&gt; &#039;\u8ffd\u52a0&#039;, &#039;permission&#039; =&gt; &#039;write&#039;],\n          &#039;edit&#039; =&gt; [&#039;label&#039; =&gt; &#039;\u7de8\u96c6&#039;, &#039;permission&#039; =&gt; &#039;write&#039;],\n        ] as $page =&gt; $conf)\n          {{-- \u6a29\u9650\u306e\u6709\u7121\u3067\u9805\u76ee\u3092\u8868\u793a\u30fb\u975e\u8868\u793a\u306b\u3059\u308b --}}\n          @can(&quot;$module.${conf[&#039;permission&#039;]}&quot;)\n            &lt;li class=&#039;feature-tab&#039;\n              :class=&quot;{\n                &#039;bg-white&#039;: activeFeature === &#039;{{ $module }}-{{ $page }}&#039;,\n                &#039;bg-gray-400 hover:bg-gray-200&#039;: activeFeature !== &#039;{{ $module }}-{{ $page }}&#039;\n              }&quot;\n            &gt;\n              &lt;a href=&#039;{{ route(&quot;web.{$module}.{$page}&quot;) }}&#039; id=&#039;{{ $module }}-{{ $page }}-tab&#039; role=&#039;tab&#039;\n                @click.prevent=&quot;selectTab(event)&quot;\n              &gt;\n                {{ $conf[&#039;label&#039;] }}\n              &lt;\/a&gt;\n            &lt;\/li&gt;\n          @endcan\n        @endforeach\n        &lt;li class=&#039;feature-tab bg-gray-400&#039; x-text=&quot;activeFeature&quot;&gt;\n        &lt;\/li&gt;\n      &lt;\/ul&gt;\n    &lt;\/nav&gt;\n    \n    &lt;div class=&#039;features&#039;\n      {{-- oligo\u30e2\u30b8\u30e5\u30fc\u30eb\u5168\u4f53\u3067\u4f7f\u7528\u3067\u304d\u308b\u3088\u3046\u306b\u3053\u3053\u306bx-data\u3092\u5b9a\u7fa9\u3059\u308b --}}\n      x-data=&quot;{\n        items: [], \/\/ \u30c6\u30fc\u30d6\u30eb\u304b\u3089\u62bd\u51fa\u3055\u308c\u305f\u30c7\u30fc\u30bf\u3002\u4eca\u5f8c\u66f4\u65b0\u3084\u524a\u9664\u306e\u6a5f\u80fd\u3067\u3082\u4f7f\u7528\u3067\u304d\u308b\u3088\u3046\u306b\u3001\u3053\u3053(#features)\u306b\u5b9a\u7fa9\u3059\u308b\u3002\n        query: {}, \/\/ \u691c\u7d22\u306e\u6761\u4ef6\u3002x-model\u3068\u3057\u3066\u8a2d\u5b9a\u3059\u308b\u3053\u3068\u3067\u5165\u529b\u30d5\u30a9\u30fc\u30e0\u306e\u5024\u304c\u305d\u306e\u307e\u307eJavascript\u3067\u4f7f\u7528\u3067\u304d\u308b\n \n        \/\/ \u691c\u7d22 fetch\u306f\u975e\u540c\u671f(async)\u306b\u5b9f\u884c\u3055\u308c\u308b\u306e\u3067\u3001\u305d\u308c\u306b\u305d\u308d\u3048\u308b\n        async search(){\n          const parameter = new URLSearchParams(this.query);  \/\/ \u540c\u3058x-data\u5185\u306a\u306e\u3067 this.query\u3068\u306a\u308b\u3002\u3053\u308c\u3092GET\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc(?key1=value1&amp;key2=value2)\u306b\u5909\u63db\u3059\u308b\n          console.log(&#039;parameter:&#039;, parameter.toString());  \/\/ \u52d5\u4f5c\u78ba\u8a8d\n          const options = {\n            method: &#039;GET&#039;,\n            headers: {\n              &#039;Accept&#039;: &#039;application\/json&#039;,  \/\/ \u8fd4\u308a\u5024\u306e\u8a2d\u5b9a\u3002Laravel\u304c\u5224\u65ad\u3059\u308b\u306e\u306b\u4f7f\u3046\u3002\n              &#039;Content-Type&#039;: &#039;application\/json&#039;,\n            },\n          };\n \n          return fetch(&#039;{{ route(&quot;web.{$module}.search&quot;) }}?&#039; + parameter.toString(), options)\n            .then(response =&gt; response.json())\n            .then(response =&gt; {\n              console.log(&#039;search done&#039;, response);  \/\/ \u52d5\u4f5c\u78ba\u8a8d\n              return this.append(response.data.items);  \/\/ items\u3092\u7f6e\u304d\u63db\u3048\u308bappend\u3092\u547c\u3076\n            })\n            .catch(error =&gt; {debug(error)})\n          ;\n        },\n \n        \/\/ \u691c\u7d22\u7d50\u679c\u3092items\u306b\u53cd\u6620\u3055\u305b\u308b\u3002\u4eca\u5f8c\u3001\u65b0\u3057\u3044\u691c\u7d22\u7d50\u679c\u3067\u7f6e\u304d\u63db\u3048\u308b\u306e\u3067\u306f\u306a\u304f\u3001\u8ffd\u52a0\u3059\u308b\u3088\u3046\u306b\u4fee\u6b63\u3057\u3066\u3044\u304f\u306e\u3067\u3001append\u3068\u3057\u3066\u3042\u308b\u3002\n        append(items){\n          console.log(&#039;append:&#039;, items);\n          this.items = items;\n        },\n \n        \/\/ \u30c1\u30a7\u30c3\u30af\u304c\u3044\u308c\u3089\u308c\u305f\u3082\u306e\u3060\u3051\u3092\u53d6\u5f97\u3059\u308b\u3002\n        get checked(){\n          return this.items.filter(item =&gt; item.checked);\n        },\n        get hasChecked(){\n          return this.checked.length &gt; 0;\n        }\n      }&quot;\n    &gt;\n      @yield(&#039;feature&#039;)\n    &lt;\/div&gt;\n  &lt;\/x-module&gt;\n@endsection\n<\/pre>\n<\/div>\n<h2>\u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u6295\u5165<\/h2>\n<p>\u30b7\u30b9\u30c6\u30e0\u306e\u52d5\u4f5c\u306b\u5fc5\u8981\u306a\u30c7\u30fc\u30bf\u3084\u3001\u30c6\u30b9\u30c8\u7528\u306e\u30c7\u30fc\u30bf\u3092\u3044\u308c\u308b\u3053\u3068\u3092seeder (\u7a2e\u3092\u307e\u304f\u4eba) \u3068\u3044\u3044\u307e\u3059\u3002\n\u4eca\u56de\u306f\u30c6\u30b9\u30c8\u7528\u306e\u30e6\u30fc\u30b6\u30fc\u3068\u30ed\u30fc\u30eb\u3001\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306e\u30c7\u30fc\u30bf\u3092\u6295\u5165\u3057\u307e\u3059\u3002<\/p>\n<p>\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306f\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u4e2d\u306b\u66f8\u304d\u8fbc\u3093\u3067\u3042\u308b\u306e\u3067\u3001\u30c6\u30fc\u30d6\u30eb\u306b\u3044\u308c\u3066\u30ed\u30fc\u30eb\u306b\u4ed8\u4e0e\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u304a\u304b\u306a\u3044\u3068\u610f\u5473\u304c\u3042\u308a\u307e\u305b\u3093\u3002\n\u672c\u756a\u74b0\u5883\u306b\u3082\u5fc5\u8981\u306a\u306e\u3067\u3001\u65b0\u3057\u3044\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3073\u306bseeder\u306b\u8a2d\u5b9a\u3059\u308b\u3068\u3088\u3044\u3067\u3059\u3002\n\u4eca\u306e\u3068\u3053\u308d\u3001DatabaseSeeder\u306b\u307e\u3068\u3081\u3066\u3042\u308a\u307e\u3059\u304c\u3001PermissionSeeder\u306a\u3069\u306b\u5206\u96e2\u3059\u308b\u3068\u3088\u3044\u3067\u3059\u3002<\/p>\n<p>\u30e6\u30fc\u30b6\u30fc\u3068\u30ed\u30fc\u30eb\u306f\u30c6\u30b9\u30c8\u7528\u306b\u5fc5\u8981\u3067\u3059\u304c\u3001\u672c\u756a\u74b0\u5883\u3067\u306f\u7570\u306a\u308b\u540d\u524d\u306e\u307b\u3046\u304c\u3088\u3044\u5834\u5408\u304c\u3042\u308a\u307e\u3059\u3002\n\u7279\u306b\u30e6\u30fc\u30b6\u30fc\u306f\u3053\u306e\u307e\u307e\u3044\u308c\u306a\u3044\u3088\u3046\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">database\/seeders\/DatabaseSeeder.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace Database\\Seeders;\n \nuse App\\Models\\User;\nuse Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;\nuse Illuminate\\Database\\Seeder;\nuse Spatie\\Permission\\Models\\Permission;\nuse Spatie\\Permission\\Models\\Role;\nuse Spatie\\Permission\\PermissionRegistrar;\n \nclass DatabaseSeeder extends Seeder\n{\n    use WithoutModelEvents;\n \n    \/**\n     * Seed the application&#039;s database.\n     * php artisan db:seed\n     *\/\n    public function run(): void\n    {\n        \/\/ Permission\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u30af\u30ea\u30a2\uff08\u30b7\u30fc\u30c0\u30fc\u5b9f\u884c\u6642\u306e\u5fc5\u9808\u51e6\u7406\uff09\n        app()[PermissionRegistrar::class]-&gt;forgetCachedPermissions();\n \n        $permissions = [\n            &#039;material@web&#039; =&gt; [\n                &#039;oligo.read&#039;, &#039;oligo.write&#039;,\n                &#039;seed.read&#039;, &#039;seed.write&#039;,\n                &#039;plant.read&#039;, &#039;plant.write&#039;\n            ],\n            &#039;system@admin&#039; =&gt; [\n                &#039;user.read&#039;, &#039;user.write&#039;,\n                &#039;role.read&#039;, &#039;role.write&#039;,\n                &#039;permission.read&#039;, &#039;permission.write&#039;\n            ]\n        ];\n \n        $roles = [\n            &#039;material user@web&#039; =&gt; $permissions[&#039;material@web&#039;],\n            &#039;system admin@admin&#039; =&gt; $permissions[&#039;system@admin&#039;]\n        ];\n \n        $users = [\n            [\n                &#039;name&#039; =&gt; &#039;test user&#039;,\n                &#039;email&#039; =&gt; &#039;test@example.com&#039;,\n                &#039;password&#039; =&gt; &#039;secretuser&#039;,\n                &#039;roles&#039; =&gt; [&#039;material user&#039;],\n            ],\n            [\n                &#039;name&#039; =&gt; &#039;test admin&#039;,\n                &#039;email&#039; =&gt; &#039;admin@example.com&#039;,\n                &#039;password&#039; =&gt; &#039;secretadmin&#039;,\n                &#039;roles&#039; =&gt; [&#039;system admin&#039;],\n            ]\n        ];\n \n        \/\/ \u6a29\u9650\u3092\u8a2d\u5b9a\n        foreach($permissions as $perm_group =&gt; $perms){\n            [$label, $guard] = explode(&quot;@&quot;, $perm_group . &#039;@&#039;);\n            foreach($perms as $perm){\n                Permission::findOrCreate($perm, $guard);\n            }\n        }\n \n        \/\/ \u5f79\u5272\u3092\u8a2d\u5b9a\n        foreach($roles as $role_key =&gt; $perms){\n            [$role_name, $guard] = explode(&quot;@&quot;, $role_key . &#039;@&#039;);\n            $role = Role::findOrCreate($role_name, $guard);\n            $role-&gt;syncPermissions($perms);\n        }\n \n        \/\/ \u30e6\u30fc\u30b6\u30fc\u3092\u4f5c\u6210\n        foreach($users as $userData){\n            $roleNames = $userData[&#039;roles&#039;];\n            unset($userData[&#039;roles&#039;]);\n \n            $user = User::firstOrCreate([&#039;email&#039; =&gt; $userData[&#039;email&#039;]], $userData);\n            $roles = Role::whereIn(&#039;name&#039;, $roleNames)-&gt;get();\n            $user-&gt;syncRoles($roles);\n        }\n    }\n}\n<\/pre>\n<\/div>\n<p>\u5b9f\u884c<\/p>\n<div class='console'>\n  <pre >\n$ .\/artisan db:seed\n<\/pre>\n<\/div>\n<h2>\u6a29\u9650\u306b\u95a2\u3059\u308b\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u306e\u4f5c\u6210<\/h2>\n<p><strong>\u4ee5\u4e0b\u306f\u7b2c7\u7ae0\u3001\u7b2c8\u7ae0\u306e\u5f8c\u306b\u66f8\u3044\u3066\u3044\u307e\u3059\u3002<\/strong><\/p>\n<h3>\u30eb\u30fc\u30c8\u306e\u8a2d\u5b9a<\/h3>\n<p><code>routes\/user.php<\/code> \u3092\u30b3\u30d4\u30fc\u3057\u3066 <code>role.php<\/code> \u3068 <code>permission.php<\/code> \u3092\u4f5c\u6210\u3057\u3001admin.php\u3067\u8aad\u307f\u8fbc\u307f\u307e\u3059\u3002<\/p>\n<h3>\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u4f5c\u6210<\/h3>\n<p>\u540c\u3058\u304f <code>app\/Http\/Controllers\/UserController.php<\/code> \u3092\u30b3\u30d4\u30fc\u3057\u3066 <code>RoleController.php<\/code> \u3068 <code>PermissionController.php<\/code> \u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<p>role \u3068 permission \u3092sync \u3059\u308b\u305f\u3081\u306eupdate\u30e1\u30bd\u30c3\u30c9\u304c\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3057\u3066\u3042\u308a\u307e\u3059\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Http\/Controllers\/RoleController.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Http\\Controllers;\n \nuse Spatie\\Permission\\Models\\Role;\nuse App\\Services\\RoleService;\nuse App\\Http\\Requests\\RoleRequest;\nuse App\\Http\\Requests\\RoleSearchRequest;\nuse App\\Http\\Requests\\RolesRequest;\nuse App\\Http\\Requests\\RolesUpdateRequest;\n \nclass RoleController extends MaterialController\n{\n    protected string $singleRequest = RoleRequest::class;\n    protected string $multiRequest = RolesRequest::class;\n    protected string $queryRequest = RoleSearchRequest::class;\n \n    public function __construct(\n        protected RoleService $service,\n        protected Role $model\n    ) {}\n \n    \/\/ GET\u30ea\u30af\u30a8\u30b9\u30c8(\u30d3\u30e5\u30fc\u3092\u8fd4\u3059)\n    public function index(){\n        return $this-&gt;respond(array_merge(\n            $this-&gt;service-&gt;search([]),\n            [&#039;roles&#039; =&gt; $this-&gt;model-&gt;orderBy(&#039;name&#039;)-&gt;get()]\n        ));\n    }\n \n    \/\/ role\u306e\u8ffd\u52a0\n    public function store(){\n        try{\n            $items = app($this-&gt;multiRequest)-&gt;valids;\n            $this-&gt;service-&gt;create($items);\n            return redirect(module_route(&#039;role&#039;));\n        }catch(\\Throwable $e){\n            return $this-&gt;json([&#039;message&#039; =&gt; $e-&gt;getMessage()], 400);\n        }\n    }\n \n    \/\/ role\u306e\u4fee\u6b63\n    public function update($id = null){\n        try{\n            $data = app(RolesUpdateRequest::class)-&gt;validated();\n            return $this-&gt;service-&gt;syncUserRoles($data[&#039;users&#039;]);\n        }catch(\\Throwable $e){\n            return $this-&gt;json([&#039;message&#039; =&gt; $e-&gt;getMessage()], 400);\n        }\n    }\n}\n<\/pre>\n<\/div>\n<h3>\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u4f5c\u6210<\/h3>\n<p>RoleRequest\u3068RolesRequest\u306fOligo\u306e\u30b3\u30d4\u30fc\u305d\u306e\u307e\u307e\u3002<\/p>\n<p>\u691c\u7d22\u306fusers\u30c6\u30fc\u30d6\u30eb\u3068roles\u30c6\u30fc\u30d6\u30eb\u3092\u7d50\u5408\u3057\u3066\u3044\u308b(User::with(&#8216;roles&#8217;))\u306e\u3067\u3001\u691c\u7d22\u306e\u5b9a\u7fa9\u3092\u4e8c\u3064\u306eTableDefinition\u304b\u3089\u3068\u3063\u3066\u304f\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u308b\u3002\n\u5b9f\u969b\u306b\u306fuser.name\u3068role.name\u3060\u3051\u306a\u306e\u3067\u3001\u3053\u306e\u3088\u3046\u306b\u8907\u96d1\u306b\u3059\u308b\u5fc5\u8981\u306f\u306a\u3044\u304c\u3001\u4eca\u5f8c\u540c\u3058\u3088\u3046\u306a\u5834\u9762\u3067\u4f7f\u3048\u308b\u304b\u3082\u3057\u308c\u306a\u3044\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Http\/Requests\/RoleSearchRequest.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Http\\Requests;\n \nuse Illuminate\\Foundation\\Http\\FormRequest;\nuse App\\TableDefinitions\\RoleTableDefinition;\nuse App\\TableDefinitions\\UserTableDefinition;\n \nclass RoleSearchRequest extends FormRequest\n{\n    public function rules(RoleTableDefinition $table): array\n    {\n        $merges_rules = [];\n        foreach([\n            &#039;user&#039; =&gt; app(UserTableDefinition::class)-&gt;searchRules(),\n            &#039;role&#039; =&gt; $table-&gt;searchRules()\n        ] as $table =&gt; $rules){\n            foreach($rules as $key =&gt; $value){\n                $merges_rules[&quot;${table}_$key&quot;] = $value;\n            }\n        }\n        return $merges_rules;\n    }\n}\n\/*\n \n    use App\\Http\\Requests\\RoleSearchRequest;\n    $request = app(RoleSearchRequest::class);\n    app()-&gt;call([$request, &#039;rules&#039;]);\n \n*\/\n<\/pre>\n<\/div>\n<p>\u8907\u6570\u30e6\u30fc\u30b6\u30fc\u306e\u30ed\u30fc\u30eb\u3092\u307e\u3068\u3081\u3066\u5909\u66f4\u3059\u308b\u305f\u3081\u306eRolesUpdateRequest\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Http\/Requests\/RolesUpdateRequest.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Http\\Requests;\n \nuse Illuminate\\Contracts\\Validation\\ValidationRule;\nuse Illuminate\\Foundation\\Http\\FormRequest;\nuse Illuminate\\Validation\\Rule;\n \nclass RolesUpdateRequest extends FormRequest\n{\n    public function rules(): array\n    {\n        return [\n            &#039;guard_name&#039; =&gt; [\n                &#039;required&#039;,\n                Rule::in(array_keys(config(&#039;auth.guards&#039;))),            &#039;users&#039; =&gt; [&#039;required&#039;, &#039;array&#039;],\n            ],\n            &#039;users.*.user_id&#039; =&gt; [&#039;required&#039;, &#039;integer&#039;, &#039;exists:users,id&#039;],\n            &#039;users.*.roles&#039; =&gt; [&#039;present&#039;, &#039;array&#039;],\n            &#039;users.*.roles.*&#039; =&gt; [&#039;integer&#039;, &#039;exists:roles,id&#039;]\n        ];\n    }\n}\n<\/pre>\n<\/div>\n<p>Permission\u306e\u307b\u3046\u3082\u57fa\u672c\u7684\u306b\u540c\u3058<\/p>\n<h3>\u30b5\u30fc\u30d3\u30b9\u306e\u4f5c\u6210<\/h3>\n<p>role\u306fuser\u30c6\u30fc\u30d6\u30eb\u3068\u3001permission\u306frole\u30c6\u30fc\u30d6\u30eb\u3068\u30ea\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u3068\u308b\u306e\u3067\u3001search\u30e1\u30bd\u30c3\u30c9\u304c\u5c11\u3057\u5909\u308f\u3063\u3066\u304d\u307e\u3059\u3002<\/p>\n<p>\u7d50\u5c40users\u306ename\u3068roles\u306ename\u3057\u304b\u691c\u7d22\u5bfe\u8c61\u306b\u3057\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u3053\u3053\u307e\u3067\u8907\u96d1\u306b\u3059\u308b\u5fc5\u8981\u3082\u306a\u3044\u304b\u3068\u601d\u3044\u307e\u3059\u3002\n\u7d20\u76f4\u306b$builder-&gt;where(&#8216;name&#8217;, ) \/* users\u7528\u306e\u691c\u7d22 <em>\/-&gt;whereHas(&#8216;roles&#8217;, fn($q) =&gt; $q-&gt;where(&#8216;name&#8217;, )) \/<\/em> roles\u7528\u306e\u691c\u7d22 *\/ \u3068\u66f8\u304f\u307b\u3046\u304c\u308f\u304b\u308a\u3084\u3059\u304f\u3066\u3088\u3044\u3067\u3059\u3002<\/p>\n<p>syncUserRoles\u306f\u8907\u6570\u306e\u30e6\u30fc\u30b6\u30fc\u306e\u30ed\u30fc\u30eb\u3092\u8a2d\u5b9a(sync)\u3057\u3066\u3044\u307e\u3059\u3002\nsync\u306f\u3044\u3063\u305f\u3093\u5168\u524a\u9664\u3057\u3066\u3001\u8ffd\u52a0\u3059\u308b\u3068\u3044\u3046\u3053\u3068\u3092\u3057\u3066\u3044\u308b\u306e\u3067\u3001SQL\u304c\u305f\u304f\u3055\u3093\u767a\u884c\u3055\u308c\u3066\u3044\u307e\u3059\u3002\n\u305d\u306e\u305f\u3081\u3001\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u3092\u8a2d\u5b9a\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>\u6700\u5f8c\u306e\u8fd4\u308a\u5024\u3092 $this-&gt;search() \u3068\u3067\u304d\u308b\u3068\u304b\u3063\u3053\u3044\u3044\u3067\u3059\u306d\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Services\/RoleService.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Services;\n \nuse App\\Models\\User;\nuse Spatie\\Permission\\Models\\Role;\nuse Illuminate\\Support\\Facades\\DB;\nuse App\\TableDefinitions\\RoleTableDefinition;\nuse App\\TableDefinitions\\UserTableDefinition;\nuse App\\TableSearch\\SearchFactory;\n \nclass RoleService extends MaterialService\n{\n    public function __construct(\n        protected Role $model,\n        public RoleTableDefinition $table,\n        public UserTableDefinition $user_table,\n        protected SearchFactory $searchFactory\n    ){}\n \n    public function search(array $query)\n    {\n    \t$builder = User::with(&#039;roles&#039;);\n \n        foreach ($query as $column =&gt; $value) {\n \n            if (is_string($value) &amp;&amp; trim($value) === &#039;&#039;){\n                continue;\n            }\n \n            \/\/ \u30c6\u30fc\u30d6\u30eb\u306e\u5b9a\u7fa9\u304b\u3089\u3001\u5217\u306e\u60c5\u5831\u3092\u53d6\u5f97\u3059\u308b\n            switch($column){\n            case &#039;user_name&#039;:\n                $definition = $this-&gt;user_table-&gt;column(&#039;name&#039;);\n                break;\n            case &#039;role_name&#039;:\n                $definition = $this-&gt;table-&gt;column(&#039;name&#039;);\n                break;\n            }\n \n            if (!$definition) {\n                continue;\n            }\n \n            \/\/ \u691c\u7d22\u306e\u7a2e\u985e\u3092\u53d6\u5f97\u3059\u308b\n            $type = $definition[&#039;search&#039;][&#039;type&#039;] ?? null;\n            if (!$type) {\n                continue;\n            }\n            #var_dump($column, $value, $definition, $type);\n \n            try{\n                $searcher = $this-&gt;searchFactory-&gt;make($type);\n                switch($column){\n                case &#039;user_name&#039;:\n                    $searcher-&gt;apply($builder, &#039;name&#039;, $value);\n                    break;\n                case &#039;role_name&#039;:\n                    $builder-&gt;whereHas(&#039;roles&#039;,\n                        fn($q) =&gt; $searcher-&gt;apply($q, &#039;name&#039;, $value)\n                    );\n                    break;\n                }\n            }catch(\\Throwable $e){\n                continue;\n            }\n        }\n \n        return [\n            &#039;items&#039; =&gt; $builder-&gt;orderBy(&#039;created_at&#039;, &#039;desc&#039;)-&gt;get(),\n            &#039;sql&#039; =&gt; $builder-&gt;toSql(),\n            &#039;query&#039; =&gt; $query\n        ];\n    }\n \n    public function syncUserRoles(array $assignments)\n    {\n        #var_dump($assignments);\n        $user_ids = DB::transaction(function () use ($assignments){\n            $user_ids = [];\n            foreach($assignments as $user_roles){\n                $user = User::findOrFail($user_roles[&#039;user_id&#039;]);\n                $roles = Role::whereIn(&#039;id&#039;, $user_roles[&#039;roles&#039;])-&gt;get();\n                $user-&gt;syncRoles($roles);\n                $user_ids[] = $user-&gt;id;\n            }\n            return $user_ids;\n        });\n    \treturn [\n            &#039;users&#039; =&gt; User::with(&#039;roles&#039;)\n                -&gt;whereIn(&#039;id&#039;, $user_ids)\n                -&gt;orderBy(&#039;created_at&#039;, &#039;desc&#039;)\n                -&gt;get()\n        ];\n    }\n}\n \n\/*\n \n$service = app(\\App\\Services\\RoleService::class);\n$results = $service-&gt;search([&#039;role.name&#039; =&gt; &#039;admin&#039;]);\n$results[&#039;sql&#039;]\n \n\n*\/\n<\/pre>\n<\/div>\n<p>\u4f3c\u305f\u3088\u3046\u306a\u3082\u306e\u3067\u3059\u304c\u3001PermissionService\u306f\u3053\u306e\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">app\/Services\/PermissionService.php<\/h5>\n<pre >\n&lt;?php\n \nnamespace App\\Services;\n \nuse Spatie\\Permission\\Models\\Permission;\nuse Spatie\\Permission\\Models\\Role;\nuse Illuminate\\Support\\Facades\\DB;\nuse App\\TableDefinitions\\PermissionTableDefinition;\nuse App\\TableDefinitions\\RoleTableDefinition;\nuse App\\TableSearch\\SearchFactory;\n \nclass PermissionService extends MaterialService\n{\n    public function __construct(\n        protected Permission $model,\n        public PermissionTableDefinition $table,\n        public RoleTableDefinition $role_table,\n        protected SearchFactory $searchFactory\n    ){}\n \n    public function search(array $query)\n    {\n    \t$builder = Role::with([&#039;users&#039;, &#039;permissions&#039;]);\n \n        foreach ($query as $column =&gt; $value) {\n \n            if (is_string($value) &amp;&amp; trim($value) === &#039;&#039;){\n                continue;\n            }\n \n            \/\/ \u30c6\u30fc\u30d6\u30eb\u306e\u5b9a\u7fa9\u304b\u3089\u3001\u5217\u306e\u60c5\u5831\u3092\u53d6\u5f97\u3059\u308b\n            switch($column){\n            case &#039;permission_name&#039;:\n                $definition = $this-&gt;table-&gt;column(&#039;name&#039;);\n                break;\n            default:\n                $definition = $this-&gt;role_table-&gt;column($column);\n                break;\n            }\n \n            if (!$definition) {\n                continue;\n            }\n \n            \/\/ \u691c\u7d22\u306e\u7a2e\u985e\u3092\u53d6\u5f97\u3059\u308b\n            $type = $definition[&#039;search&#039;][&#039;type&#039;] ?? null;\n            if (!$type) {\n                continue;\n            }\n \n            \/\/ \u691c\u7d22\u306e\u7a2e\u985e\u306b\u5fdc\u3058\u3066\u3001\u691c\u7d22\u3092\u9069\u7528\u3059\u308b\n            try{\n                $searcher = $this-&gt;searchFactory-&gt;make($type);\n                switch($column){\n                case &#039;permission_name&#039;:\n                    $builder-&gt;whereHas(&#039;permissions&#039;,\n                        fn($q) =&gt; $searcher-&gt;apply($q, &#039;name&#039;, $value)\n                    );\n                    break;\n \n                default:\n                    $searcher-&gt;apply($builder, $column, $value);\n                    break;\n                }\n \n            }catch(\\Throwable $e){\n                continue;\n            }\n        }\n \n        return [\n            &#039;items&#039; =&gt; $builder-&gt;orderBy(&#039;created_at&#039;, &#039;desc&#039;)-&gt;get(),\n            &#039;sql&#039; =&gt; $builder-&gt;toSql(),\n            &#039;query&#039; =&gt; $query\n        ];\n    }\n \n    public function syncRolePermissions(array $assignments)\n    {\n        $role_ids = DB::transaction(function () use ($assignments){\n            $role_ids = [];\n            foreach($assignments as $role_permissions){\n                $role = Role::findOrFail($role_permissions[&#039;role_id&#039;]);\n                $permissions = Permission::whereIn(&#039;id&#039;, $role_permissions[&#039;permissions&#039;])-&gt;get();\n                $res = $role-&gt;syncPermissions($permissions);\n                $role_ids[] = $role-&gt;id;\n            }\n            return $role_ids;\n        });\n    \treturn [\n            &#039;roles&#039; =&gt; Role::with([&#039;users&#039;, &#039;permissions&#039;])\n                -&gt;whereIn(&#039;id&#039;, $role_ids)\n                -&gt;orderBy(&#039;created_at&#039;, &#039;desc&#039;)\n                -&gt;get()\n        ];\n    }\n}\n \n\/*\n  use App\\Services\\PermissionService;\nuse Spatie\\Permission\\Models\\Permission;\nuse Spatie\\Permission\\Models\\Role;\n  $service = app(PermissionService::class);\n  $service-&gt;syncRolePermissions([[&quot;role_id&quot; =&gt; 16,&quot;permissions&quot; =&gt; [28, 27]]]);\n \n  Role::with([&#039;permissions&#039;])-&gt;whereIn(&#039;id&#039;, [16])-&gt;get()-&gt;first()-&gt;permissions\n \n        ],\n    ],\n]);\n \nRole::find(16);\nPermission::whereIn(&#039;id&#039;, [28, 27])-&gt;get();\n \n\n \nuse Spatie\\Permission\\Models\\Permission;\nuse Spatie\\Permission\\Models\\Role;\n \n*\/\n<\/pre>\n<\/div>\n<h3>\u30ed\u30fc\u30eb\u306e\u30d3\u30e5\u30fc\u306e\u4f5c\u6210<\/h3>\n<p>\u30e6\u30fc\u30b6\u30fc\u3068\u30ed\u30fc\u30eb\u306e\u95a2\u4fc2\u3092 userRolesMap\u3068\u3044\u3046\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u3044\u308c\u308b\u3002\n\u3053\u308c\u3092\u64cd\u4f5c\u3059\u308b\u305f\u3081\u306e\u95a2\u6570\u3068\u3044\u3063\u3057\u3087\u306b x-data\u306b\u767b\u9332\u3057\u3066\u3044\u308b\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">resources\/views\/role\/module.blade.php<\/h5>\n<pre >\n@extends(&#039;layouts.app&#039;)\n \n@section(&#039;module&#039;)\n  &lt;x-module id=&#039;{{ $module_id }}&#039;&gt;\n    &lt;div class=&#039;features&#039;\n      x-data=&quot;Material.makeModulePanel({\n        query_template: @js([\n          &#039;user_name&#039; =&gt; [&#039;value&#039; =&gt; &#039;&#039;, &#039;mode&#039; =&gt; &#039;regex&#039;],\n          &#039;role_name&#039; =&gt; &#039;&#039;\n        ]),\n        url: {\n          search: &#039;{{ module_route($module_id, &quot;search&quot;) }}&#039;,\n          store:  &#039;{{ module_route($module_id, &quot;store&quot;) }}&#039;,\n          update: &#039;{{ module_route($module_id, &quot;index&quot;) }}&#039;,\n        },\n \n        roles: [],  \/\/ \u5229\u7528\u53ef\u80fd\u306a\u5168\u30ed\u30fc\u30eb\n        userRolesMap: {}, \/\/ \u7de8\u96c6\u7528\u306e\u30c7\u30fc\u30bf { user_id: [roles]} \u306e\u9023\u60f3\u914d\u5217\n \n        groupedRoles(){\n          return Object.groupBy(\n            this.roles, \/\/ \u7a7a\u6587\u5b57\u5217\u3092\u9664\u5916\n            role =&gt; role.guard_name\n          );\n        },\n \n        updateRole(){\n          console.log(&#039;post&#039;, JSON.stringify(this.checkedItems.map(\n                item =&gt; ({\n                  user_id: Number(item.id),\n                  roles: this.userRolesMap[item.id] || []\n                })\n              )));\n          return api.put(\n            this.url.update,\n            {\n              users: this.checkedItems.map(\n                item =&gt; ({\n                  user_id: Number(item.id),\n                  roles: this.userRolesMap[item.id] || []\n                })\n              ),\n            }\n          );\n        },\n \n        \/\/ --- \u30ed\u30fc\u30eb\u4e00\u62ec\u64cd\u4f5c\u306e\u5224\u5b9a\u30ed\u30b8\u30c3\u30af ---\n        havingCount(roleId) {\n          if (this.checkedItems.length === 0) return 0;\n\/\/          this.checkedItems.forEach(item =&gt; console.log(&#039;havingCount:&#039;, this.userRolesMap, this.userRolesMap[item.id], roleId));\n          return this.checkedItems.filter(\n            item =&gt; (this.userRolesMap[item.id] || [])\n              .includes(roleId)\n          ).length;\n        },\n        isAllHas(roleId) {\n            return this.checkedItems.length &gt; 0 &amp;&amp; this.havingCount(roleId) \n              === this.checkedItems.length;\n        },\n        isAnyHas(roleId) {\n            const count = this.havingCount(roleId);\n            return count &gt; 0 &amp;&amp; count &lt; this.checkedItems.length;\n        },\n        \n        \/\/ \u3069\u3046\u3059\u308b\u306e\u304c\u3088\u3044\u304b\u6c7a\u3081\u304b\u306d\u3066\u3044\u308b\n        remove(roleId){\n          api.post(&#039;{{ module_route($module_id) }}&#039;, {ids:[roleId]});\n        },\n \n        \/\/ --- \u30ed\u30fc\u30eb\u306e\u5207\u308a\u66ff\u3048\u51e6\u7406 ---\n        toggleRole(roleId, isChecked) {\n            this.checkedItems.forEach(item =&gt; {\n                let currentRoles = this.userRolesMap[item.id] || [];\n                if (isChecked) {\n                    \/\/ \u91cd\u8907\u3092\u9632\u3044\u3067\u8ffd\u52a0\n                    if (!currentRoles.includes(roleId)) {\n                        this.userRolesMap[item.id] = [...currentRoles, roleId];\n                    }\n                } else {\n                    \/\/ \u524a\u9664\n                    this.userRolesMap[item.id] = currentRoles.filter(id =&gt; id !== roleId);\n                }\n            });\n        },\n        init() {\n          this.resetQuery();\n \n          this.$watch(&#039;items&#039;, (newItems) =&gt; {\n            console.log(&#039;items change was detected&#039;);\n            newItems.forEach(item =&gt; {\n              if(! this.userRolesMap[item.id]){\n                this.userRolesMap[item.id]\n                  = (item.roles || []).map(role =&gt; role.id);\n              }\n            });\n          })\n        }\n      })&quot; {{-- Material.makeModulePanel\u3092\u9589\u3058\u308b\u3002x-data\u3092\u9589\u3058\u308b --}}\n    &gt;\n      @yield(&#039;feature&#039;)\n    &lt;\/div&gt;\n  &lt;\/x-module&gt;\n@endsection\n<\/pre>\n<\/div>\n<p>\u4e00\u753b\u9762\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u3068\u30ed\u30fc\u30eb\u3092\u8a2d\u5b9a\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u308b\u3002\n\u5de6\u306b\u30e6\u30fc\u30b6\u30fc\u4e00\u89a7\u3001\u53f3\u306b\u30ed\u30fc\u30eb\u4e00\u89a7\u3092\u914d\u7f6e\u3057\u3001\u30c1\u30a7\u30c3\u30af\u3067\u95a2\u4fc2\u3092\u3064\u304f\u308b\u3002<\/p>\n<p>\u30ed\u30fc\u30eb\u306e\u8ffd\u52a0\u306f\u753b\u9762\u306e\u66f8\u304d\u63db\u3048\u308b\u3068\u3053\u308d\u304c\u591a\u3044\u306e\u3067\u3001POST\u3057\u3066\u3001\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u3067\u5143\u306e\u753b\u9762\u3092\u66f8\u304d\u63db\u3048\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u308b\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">resources\/views\/role\/index.blade.php<\/h5>\n<pre >\n@extends(&quot;$module_id.module&quot;)\n@section(&#039;feature&#039;)\n  &lt;x-feature id=&#039;{{ $feature_id }}&#039; class=&#039;feature-index&#039;&gt;\n    &lt;div class=&#039;flex item-start gap-6&#039;\n      x-init=&quot;\n        roles = @js($roles);\n        items = @js($items);\n        \/\/ \u30c7\u30d0\u30c3\u30b0\u7528items.forEach(item =&gt; item.checked = true);\n      &quot;\n    &gt;\n      &lt;div id=&#039;left_column&#039; class=&#039;&#039;&gt;\n        &lt;h3&gt;\u30e6\u30fc\u30b6\u9078\u629e&lt;\/h3&gt;\n        &lt;table class=&#039;material-list&#039;&gt;\n          &lt;thead&gt;\n            {{-- thead 1\u884c\u76ee \u898b\u51fa\u3057 --}}\n            &lt;tr class=&#039;query&#039;&gt;\n              &lt;th&gt;&lt;\/th&gt;\n              &lt;th class=&#039;w-36&#039;&gt;\u30e6\u30fc\u30b6\u30fc\u540d&lt;\/th&gt;\n              &lt;th class=&#039;w-72&#039;&gt;\u5909\u66f4\u524d\u5f79\u5272&lt;\/th&gt;\n              &lt;th class=&#039;w-72&#039;&gt;\u5909\u66f4\u5f8c\u5f79\u5272&lt;\/th&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 2\u884c\u76ee \u30d5\u30a9\u30fc\u30e0 --}}\n            &lt;tr @input.debounce.500=&quot;search()&quot; class=&quot;query border-b-2 align-text-top&quot;&gt;\n              &lt;th&gt;\u691c\u7d22&lt;\/th&gt;\n \n              {{-- TableDefinition\u30af\u30e9\u30b9\u304b\u3089index\u306e\u30d3\u30e5\u30fc\u3067\u4f7f\u7528\u3059\u308b\u30ab\u30e9\u30e0\u3092\u53d6\u5f97\u3059\u308b --}}\n                &lt;td class=&quot;name&quot;&gt;\n                  &lt;input x-model=&quot;query.user_name.value&quot;&gt;\n                  &lt;label&gt;\n                    &lt;input type=&quot;checkbox&quot; x-model=&quot;query.user_name.mode&quot; value=1 title=&quot;\u6b63\u898f\u8868\u73fe&quot;&gt;\n                    \u6b63\u898f\u8868\u73fe\n                  &lt;\/label&gt;\n                &lt;\/td&gt;\n                &lt;td class=&quot;role&quot;&gt;\n                  &lt;input x-model=&quot;query.role_name&quot; placeholder=&quot;role_name&quot;&gt;\n                &lt;\/td&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 3\u884c\u76ee \u30dc\u30bf\u30f3 --}}\n            &lt;tr&gt;\n              &lt;td colspan=&quot;9&quot; class=&#039;px-2 py-2&#039;&gt;\n                &lt;button @click=&quot;search()&quot;&gt;  {{-- @input\u3067\u81ea\u52d5\u5b9f\u884c\u3055\u308c\u308b\u304c\u3001\u30dc\u30bf\u30f3\u3082\u52a0\u3048\u3066\u304a\u304f --}}\n                  \u691c\u7d22\n                  &lt;x-ajax-state var=&#039;query&#039; \/&gt;\n                &lt;\/button&gt;\n \n                {{-- \u30c1\u30a7\u30c3\u30af\u30dc\u30bf\u30f3\u3067\u9078\u629e\u30fb\u975e\u9078\u629e\u3092\u3059\u308b --}}\n                &lt;button @click.prevent=&quot;\n                  items.forEach(item =&gt; item.checked = !item.checked);\n                  console.log(&#039;check reverse&#039;, items.length, checkedItems.length, hasChecked);\n                &quot;&gt;\n                  \u30c1\u30a7\u30c3\u30af\u3092\u53cd\u8ee2\n                &lt;\/button&gt;\n \n                &lt;button @click=&quot;resetQuery();&quot;&gt;\u6761\u4ef6\u30af\u30ea\u30a2&lt;\/button&gt;\n              &lt;\/td&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 4\u884c\u76ee \u691c\u7d22\u7d50\u679c --}}\n            &lt;tr class=&#039;border-b-2&#039;&gt;\n              &lt;td x-show=&quot;items.length == 0&quot; colspan=&quot;9&quot;&gt;\n                \u6761\u4ef6\u306b\u5408\u3046\u3082\u306e\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n              &lt;\/td&gt;\n              &lt;td x-show=&quot;items.length &gt; 0&quot; colspan=&quot;9&quot;&gt;\n                \u691c\u7d22\u7d50\u679c: &lt;span x-text=&quot;items.length&quot;&gt;&lt;\/span&gt;\u4ef6\n                (\u2611: &lt;span x-text=&quot;checkedItems.length&quot;&gt;&lt;\/span&gt;\u4ef6)\n \n                {{-- \u4ee5\u4e0b\u306f\u958b\u767a\u7528\u306b\u3064\u304f\u3063\u3066\u3042\u308b\u306e\u3067\u3001\u672c\u756a\u3067\u306f\u524a\u9664\u3057\u305f\u307b\u3046\u304c\u3088\u3044\u304b\u3082\u3057\u308c\u306a\u3044 --}}\n                query:\n                &lt;template x-for=&quot;key in Object.keys(query)&quot; :key=&quot;key&quot;&gt;\n                  &lt;template x-if=&quot;query[key] !== undefined &amp;&amp; query[key] !== &#039;&#039;&quot;&gt;\n                    &lt;span x-text=&quot;`${key}=`+JSON.stringify(query[key])&quot;&gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/template&gt;\n              &lt;\/td&gt;\n            &lt;\/tr&gt;\n          &lt;\/thead&gt;\n \n          &lt;tbody&gt;\n            {{-- \u691c\u7d22\u7d50\u679c --}}\n            {{-- Alpine.js (x-for)\u306b\u3088\u3063\u3066\u3001items\u914d\u5217\u306e\u305d\u308c\u305e\u308c\u306e\u8981\u7d20\u3092item\u306b\u53d6\u308a\u51fa\u3057\u3001template\u8981\u7d20\u3092\u5897\u3084\u3059 --}}\n            &lt;template x-for=&quot;item in items&quot; :key=&quot;item.id&quot;&gt;\n              &lt;tr @click=&quot;item.checked = !item.checked&quot;&gt;\n                &lt;td&gt;&lt;input x-model=&quot;item.checked&quot; @click.stop type=&#039;checkbox&#039;&gt;&lt;\/td&gt;\n                &lt;td x-text=&quot;item.name&quot; class=&quot;name&quot;&gt;&lt;\/td&gt;\n                &lt;!-- \u5909\u66f4\u524d\u5f79\u5272 --&gt;\n                &lt;td&gt;\n                  &lt;template x-for=&quot;role in item.roles&quot; :key=&quot;role.id&quot;&gt;\n                    &lt;span x-text=&quot;role.name&quot;\n                      style=&quot;display:inline-block; background:#eee; padding:2px 6px; margin-right:4px; border-radius:4px;&quot;\n                    &gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/td&gt;\n                &lt;!-- \u5909\u66f4\u5f8c\u5f79\u5272 --&gt;\n                &lt;td&gt;\n                  &lt;template x-for=&quot;roleId in (userRolesMap[item.id] || [])&quot; :key=&quot;roleId&quot;&gt;\n                    &lt;span x-text=&quot;roles.find(r =&gt; r.id === roleId)?.name&quot;\n                      style=&quot;display:inline-block; background:#eee; padding:2px 6px; margin-right:4px; border-radius:4px;&quot;\n                    &gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/td&gt;\n              &lt;\/tr&gt;\n            &lt;\/template&gt;\n          &lt;\/tbody&gt;\n        &lt;\/table&gt;\n \n        &lt;button type=&#039;submit&#039; title=&quot;\u30e6\u30fc\u30b6\u30fc\u306e\u5f79\u5272\u3092\u66f4\u65b0\u3057\u307e\u3059&quot;\n          :disabled=&quot;checkedItems.length &lt; 1&quot;\n          @click=&quot;updateRole().then(data =&gt; {\n            console.log(&#039;after updateRole&#039;, data.users);\n            const ids = new Set(data.users.map(user =&gt; Number(user.id)));\n            items = items.filter(item =&gt; !ids.has(item.id));\n            return append(data.users.map(user =&gt; {\n              user.checked = true;\n              return user;\n            }));\n          })&quot;\n        &gt;\n          \u66f4\u65b0\n        &lt;\/button&gt;\n      &lt;\/div&gt;  &lt;!-- end of left_colum --&gt;\n \n      &lt;div id=&#039;right_column&#039; class=&#039;w-[30%]&#039;&gt;\n        &lt;!-- role\u306e\u4e00\u89a7 --&gt;\n        &lt;h3&gt;\u4f5c\u6210\u6e08\u307f\u5f79\u5272&lt;\/h3&gt;\n        &lt;template x-for=&quot;(subroles, group_name) in groupedRoles()&quot; :key=&quot;group_name&quot;&gt;\n          &lt;fieldset class=&quot;border border-user p-4 rounded mb-4&quot;&gt;\n            &lt;legend class=&quot;px-2 font-bold&quot;&gt;\n              &lt;label&gt;\n                &lt;input type=&#039;checkbox&#039; checked=&#039;&#039; class=&#039;accent-user&#039;&gt;\n                Guard: &lt;span x-text=&quot;group_name&quot;&gt;&lt;\/span&gt;\n              &lt;\/label&gt;\n            &lt;\/legend&gt;\n            &lt;div class=&#039;flex flex-wrap gap-4 mt-2&#039;&gt;\n              &lt;template x-for=&quot;role in subroles&quot; :key=&quot;role.id&quot;&gt;\n                &lt;label class=&quot;inline-flex items-center gap-1&quot;&gt;\n                  &lt;input type=&#039;checkbox&#039;\n                    :checked=&quot;isAllHas(role.id)&quot;\n                    x-effect=&quot;$el.indeterminate = isAnyHas(role.id)&quot;\n                    @click=&quot;toggleRole(role.id, ! isAllHas(role.id))&quot;\n                  \/&gt;\n                  &lt;span x-text=&quot;role.name&quot; class=&quot;name&quot;&gt;&lt;\/span&gt;\n                  @if(1)  {{-- \u52d5\u4f5c\u78ba\u8a8d\u7528 --}}\n                    [&lt;span x-text=&quot;havingCount(role.id)&quot; &gt;&lt;\/span&gt;\n                    &lt;span x-text=&quot;isAnyHas(role.id)&quot; &gt;&lt;\/span&gt;\n                    &lt;span x-text=&quot;isAllHas(role.id)&quot; &gt;&lt;\/span&gt;]\n                  @endif\n                &lt;\/label&gt;\n              &lt;\/template&gt;\n            &lt;\/div&gt;\n          &lt;\/fieldset&gt;\n        &lt;\/template&gt;\n \n        &lt;!-- role\u306e\u8ffd\u52a0\u7528\u30d5\u30a9\u30fc\u30e0 --&gt;\n        &lt;form x-data=&quot;{entries:&#039;role1, role2&#039;, guard_name:&#039;web&#039;}&quot;\n          @submit.prevent=&quot;console.log(&#039;Store roles:&#039;, entries);\n            htmx.ajax(&#039;POST&#039;, url.store, {\n              source: $el,\n              target:&#039;#{{ $feature_id }}&#039;,\n              swap: &#039;outerHTML&#039;,\n              headers: {\n                &#039;HX-Target&#039;: &#039;feature-&#039; + &#039;{{ $feature_id }}&#039;,\n              }\n            });\n          &quot;\n        &gt;\n          @csrf\n          &lt;fieldset class=&quot;border border-user p-4 rounded mb-4&quot;&gt;\n            &lt;h4 class=&#039;mb-2&#039;&gt;Guard: \n              &lt;x-select-guard x-model=&quot;guard_name&quot; class=&quot;border-user&quot;\/&gt;\n            &lt;\/h4&gt;\n            &lt;legend class=&quot;px-2 font-bold&quot;&gt;\u5f79\u5272\u3092\u8ffd\u52a0&lt;\/legend&gt;\n            &lt;input type=&#039;input&#039; x-model=&#039;entries&#039; class=&#039;border-1 border-user p-1&#039;&gt;\n            &lt;button&gt;\u8ffd\u52a0&lt;\/button&gt;\n \n            {{-- htmx\u3067\u30d5\u30a9\u30fc\u30e0\u3092\u9001\u4fe1\u3059\u308b --}}\n            &lt;template \n              x-for=&quot;(entry, index) in entries.split(&#039;,&#039;).map(s =&gt; s.trim())&quot;\n              :key=&quot;index&quot;\n            &gt;\n              &lt;span&gt;\n                &lt;input type=&quot;hidden&quot; :name=&quot;`items[${index}][name]`&quot; :value=&quot;entry&quot;&gt;\n                &lt;input type=&quot;hidden&quot; :name=&quot;`items[${index}][guard_name]`&quot; :value=&quot;guard_name&quot;&gt;\n              &lt;\/span&gt;\n            &lt;\/template&gt;\n          &lt;\/fieldset&gt;\n        &lt;\/form&gt;\n      &lt;\/div&gt;  &lt;!-- end of right_colum role5,role6,role7--&gt;\n    &lt;\/div&gt;\n  &lt;\/x-feature&gt;\n@endsection\n@props([&#039;items&#039; =&gt; []])\n<\/pre>\n<\/div>\n<h3>\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306e\u30d3\u30e5\u30fc\u306e\u4f5c\u6210<\/h3>\n<p>\u57fa\u672c\u7684\u306b\u30ed\u30fc\u30eb\u3068\u540c\u3058\u3002\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306f\u540d\u524d\u3067\u30b0\u30eb\u30fc\u30d7\u5316\u3057\u3066\u3001\u4e00\u62ec\u30c1\u30a7\u30c3\u30af\u304c\u3067\u304d\u305f\u308a\u3001read &lt; write \u306e\u5305\u542b\u95a2\u4fc2\u3092\u81ea\u52d5\u5316\u3057\u305f\u3044\u3068\u3053\u308d\u3060\u304c\u3001\u307e\u3060\u3067\u304d\u3066\u3044\u306a\u3044\u3002<\/p>\n<p><\/p>\n<div class='code'>\n  <h5 class=\"source-file\">resources\/views\/permission\/index.blade.php<\/h5>\n<pre >\n@extends(&quot;$module_id.module&quot;)\n@section(&#039;feature&#039;)\n  &lt;x-feature id=&#039;{{ $feature_id }}&#039; class=&#039;feature-index&#039;&gt;\n    &lt;h4&gt;Guard: \n      &lt;x-select-guard x-model=&quot;query.guard_name&quot; @change=&quot;search()&quot;\n        class=&quot;border-user&quot;\n      \/&gt;\n    &lt;\/h4&gt;\n \n    &lt;div class=&#039;flex item-start gap-6&#039;\n      x-init=&quot;\n        permissions = @js($permissions);\n        console.log(@js($permissions));\n        items = @js($items);\n        \/\/ \u30c7\u30d0\u30c3\u30b0\u7528\n        search().then(() =&gt; { items.map(item =&gt; item.checked = true);});\n      &quot;\n    &gt;\n      &lt;div id=&#039;left_column&#039;&gt;\n        &lt;h3&gt;\u5f79\u5272\u9078\u629e&lt;\/h3&gt;\n        &lt;table\n          class=&#039;material-list&#039;&gt;\n          &lt;thead&gt;\n            {{-- thead 1\u884c\u76ee \u898b\u51fa\u3057 --}}\n            &lt;tr class=&#039;query&#039;&gt;\n              &lt;th&gt;&lt;\/th&gt;\n              &lt;th class=&#039;&#039;&gt;\u5f79\u5272&lt;\/th&gt;\n              &lt;th class=&#039;&#039;&gt;\u5909\u66f4\u524d\u6a29\u9650&lt;\/th&gt;\n              &lt;th class=&#039;&#039;&gt;\u5909\u66f4\u5f8c\u6a29\u9650&lt;\/th&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 2\u884c\u76ee \u30d5\u30a9\u30fc\u30e0 --}}\n            &lt;tr @input.debounce.500=&quot;search()&quot; class=&quot;query border-b-2 align-text-top&quot;&gt;\n              &lt;th&gt;\u691c\u7d22&lt;\/th&gt;\n \n              {{-- TableDefinition\u30af\u30e9\u30b9\u304b\u3089index\u306e\u30d3\u30e5\u30fc\u3067\u4f7f\u7528\u3059\u308b\u30ab\u30e9\u30e0\u3092\u53d6\u5f97\u3059\u308b --}}\n                &lt;td class=&quot;name&quot;&gt;\n                  &lt;input x-model=&quot;query.name&quot;\n                      placeholder=&quot;admin&quot;\n                  &gt;\n                &lt;\/td&gt;\n                &lt;td class=&quot;role&quot;&gt;\n                  &lt;input x-model=&quot;query.permission_name&quot;\n                    placeholder=&quot;oligo.&quot;\n                  &gt;\n                &lt;\/td&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 3\u884c\u76ee \u30dc\u30bf\u30f3 --}}\n            &lt;tr&gt;\n              &lt;td colspan=&quot;9&quot; class=&#039;px-2 py-2&#039;&gt;\n                &lt;button @click=&quot;search()&quot;&gt;  {{-- @input\u3067\u81ea\u52d5\u5b9f\u884c\u3055\u308c\u308b\u304c\u3001\u30dc\u30bf\u30f3\u3082\u52a0\u3048\u3066\u304a\u304f --}}\n                  \u691c\u7d22\n                  &lt;x-ajax-state var=&#039;query&#039; \/&gt;\n                &lt;\/button&gt;\n \n                {{-- \u30c1\u30a7\u30c3\u30af\u30dc\u30bf\u30f3\u3067\u9078\u629e\u30fb\u975e\u9078\u629e\u3092\u3059\u308b --}}\n                &lt;button @click.prevent=&quot;\n                  items.forEach(item =&gt; item.checked = !item.checked);\n                  console.log(&#039;check reverse&#039;, items.length, checkedItems.length, hasChecked);\n                &quot;&gt;\n                  \u30c1\u30a7\u30c3\u30af\u3092\u53cd\u8ee2\n                &lt;\/button&gt;\n \n                {{-- \u30c1\u30a7\u30c3\u30af\u30dc\u30bf\u30f3\u3067\u9078\u629e\u30fb\u975e\u9078\u629e\u3092\u3059\u308b --}}\n                &lt;button @click.prevent=&quot;\n                  items.forEach(item =&gt; item.checked = false);\n                &quot;&gt;\n                  \u5168\u3066\u30c1\u30a7\u30c3\u30af\u3092\u306f\u305a\u3059\n                &lt;\/button&gt;\n                \n                &lt;button @click=&quot;resetQuery();&quot;&gt;\u6761\u4ef6\u30af\u30ea\u30a2&lt;\/button&gt;\n              &lt;\/td&gt;\n            &lt;\/tr&gt;\n \n            {{-- thead 4\u884c\u76ee \u691c\u7d22\u7d50\u679c --}}\n            &lt;tr class=&#039;border-b-2&#039;&gt;\n              &lt;td x-show=&quot;items.length == 0&quot; colspan=&quot;9&quot;&gt;\n                \u6761\u4ef6\u306b\u5408\u3046\u3082\u306e\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n              &lt;\/td&gt;\n              &lt;td x-show=&quot;items.length &gt; 0&quot; colspan=&quot;9&quot;&gt;\n                \u691c\u7d22\u7d50\u679c: &lt;span x-text=&quot;items.length&quot;&gt;&lt;\/span&gt;\u4ef6\n                (\u2611: &lt;span x-text=&quot;checkedItems.length&quot;&gt;&lt;\/span&gt;\u4ef6)\n \n                {{-- \u4ee5\u4e0b\u306f\u958b\u767a\u7528\u306b\u3064\u304f\u3063\u3066\u3042\u308b\u306e\u3067\u3001\u672c\u756a\u3067\u306f\u524a\u9664\u3057\u305f\u307b\u3046\u304c\u3088\u3044\u304b\u3082\u3057\u308c\u306a\u3044 --}}\n                query:\n                &lt;template x-for=&quot;key in Object.keys(query)&quot; :key=&quot;key&quot;&gt;\n                  &lt;template x-if=&quot;query[key] !== undefined &amp;&amp; query[key] !== &#039;&#039;&quot;&gt;\n                    &lt;span x-text=&quot;key&quot;&gt;&lt;\/span&gt;=&lt;span x-text=&quot;query[key]&quot;&gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/template&gt;\n              &lt;\/td&gt;\n            &lt;\/tr&gt;\n          &lt;\/thead&gt;\n \n          &lt;tbody&gt;\n            {{-- \u691c\u7d22\u7d50\u679c --}}\n            {{-- Alpine.js (x-for)\u306b\u3088\u3063\u3066\u3001items\u914d\u5217\u306e\u305d\u308c\u305e\u308c\u306e\u8981\u7d20\u3092item\u306b\u53d6\u308a\u51fa\u3057\u3001template\u8981\u7d20\u3092\u5897\u3084\u3059 --}}\n            &lt;template x-for=&quot;item in items&quot; :key=&quot;item.id&quot;&gt;\n              &lt;tr @click=&quot;item.checked = !item.checked&quot;&gt;\n                &lt;td&gt;&lt;input x-model=&quot;item.checked&quot; @click.stop type=&#039;checkbox&#039;&gt;&lt;\/td&gt;\n                &lt;td x-text=&quot;item.name&quot; class=&quot;name&quot;&gt;&lt;\/td&gt;\n \n                &lt;!-- \u5909\u66f4\u524d\u5f79\u5272 --&gt;\n                &lt;td&gt;\n                  &lt;template x-for=&quot;permission in item.permissions&quot; :key=&quot;permission.id&quot;&gt;\n                    &lt;span x-text=&quot;permission.name&quot;\n                      style=&quot;display:inline-block; background:#eee; padding:2px 6px; margin-right:4px; border-radius:4px;&quot;\n                    &gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/td&gt;\n                &lt;!-- \u5909\u66f4\u5f8c\u5f79\u5272 --&gt;\n                &lt;td&gt;\n                  &lt;template x-for=&quot;permissionId in (rolePermissionsMap[item.id] || [])&quot; :key=&quot;permissionId&quot;&gt;\n                    &lt;span\n                      x-text=&quot;permissions.find(p =&gt; p.id === permissionId)?.name&quot;\n                      style=&quot;display:inline-block; background:#eee; padding:2px 6px; margin-right:4px; border-radius:4px;&quot;\n                    &gt;&lt;\/span&gt;\n                  &lt;\/template&gt;\n                &lt;\/td&gt;\n              &lt;\/tr&gt;\n            &lt;\/template&gt;\n          &lt;\/tbody&gt;\n        &lt;\/table&gt;\n \n        &lt;button type=&#039;submit&#039; title=&quot;\u5f79\u5272\u3068\u6a29\u9650\u3092\u66f4\u65b0\u3057\u307e\u3059&quot;\n          :disabled=&quot;checkedItems.length &lt; 1&quot;\n          @click=&quot;updatePermission().then(data =&gt; {\n            console.log(&#039;after updatePermission&#039;, data.roles);\n            const ids = new Set(data.roles.map(role =&gt; Number(role.id)));\n            items = items.filter(item =&gt; !ids.has(item.id));\n            return append(data.roles.map(role =&gt; {\n              role.checked = true;\n              return role;\n            }));\n          })&quot;\n        &gt;\n          \u66f4\u65b0\n        &lt;\/button&gt;\n      &lt;\/div&gt;  &lt;!-- end of left_colum --&gt;\n \n      &lt;div id=&#039;right_column&#039; class=&#039;w-[30%]&#039;&gt;\n        &lt;!-- permission\u306e\u4e00\u89a7 --&gt;\n        &lt;h3&gt;\u4f5c\u6210\u6e08\u307f\u6a29\u9650&lt;\/h3&gt;\n        &lt;template x-for=&quot;(subperms, group_name) in groupedPermissions()&quot; :key=&quot;group_name&quot;&gt;\n          &lt;fieldset class=&quot;border border-user p-4 rounded mb-4&quot;&gt;\n            &lt;legend class=&quot;px-2 font-bold&quot;&gt;\n              &lt;label&gt;\n                &lt;input type=&#039;checkbox&#039; checked=&#039;&#039; class=&#039;accent-user&#039;&gt;\n                &lt;span x-text=&quot;group_name&quot;&gt;&lt;\/span&gt;\n              &lt;\/label&gt;\n            &lt;\/legend&gt;\n            &lt;div class=&#039;flex flex-wrap gap-4 mt-2&#039;&gt;\n              &lt;template x-for=&quot;perm in subperms&quot; :key=&quot;perm.id&quot;&gt;\n                &lt;label class=&quot;inline-flex items-center gap-1&quot;&gt;\n                  &lt;input type=&#039;checkbox&#039;\n                    :checked=&quot;isAllHas(perm.id)&quot;\n                    x-effect=&quot;$el.indeterminate = isAnyHas(perm.id)&quot;\n                    @click=&quot;togglePermission(perm.id, ! isAllHas(perm.id))&quot;\n                  \/&gt;\n                  &lt;span x-text=&quot;perm.name.split(&#039;.&#039;).pop() + &#039; &#039; + havingCount(perm.name)&quot; class=&quot;name&quot;&gt;&lt;\/span&gt;\n                  @if(1)  {{-- \u52d5\u4f5c\u78ba\u8a8d\u7528 --}}\n                    [&lt;span x-text=&quot;havingCount(perm.id)&quot; &gt;&lt;\/span&gt;\n                    &lt;span x-text=&quot;isAnyHas(perm.id)&quot; &gt;&lt;\/span&gt;\n                    &lt;span x-text=&quot;isAllHas(perm.id)&quot; &gt;&lt;\/span&gt;]\n                  @endif\n                &lt;\/label&gt;\n              &lt;\/template&gt;\n            &lt;\/div&gt;\n          &lt;\/fieldset&gt;\n        &lt;\/template&gt;\n \n        &lt;!-- permission\u306e\u8ffd\u52a0\u7528\u30d5\u30a9\u30fc\u30e0 --&gt;\n        &lt;form x-data=&quot;{entries:&#039;some.read,some.write&#039;}&quot;\n          @submit.prevent=&quot;console.log(&#039;Store permissions:&#039;, entries);\n            htmx.ajax(&#039;POST&#039;, url.store, {\n              source: $el,\n              target:&#039;#{{ $feature_id }}&#039;,\n              swap: &#039;outerHTML&#039;,\n              headers: {\n                &#039;HX-Target&#039;: &#039;feature-&#039; + &#039;{{ $feature_id }}&#039;,\n              }\n            });\n        &quot;&gt;\n          @csrf\n          &lt;fieldset class=&quot;border border-user p-4 rounded mb-4&quot;&gt;\n            &lt;legend class=&quot;px-2 font-bold&quot;&gt;\u6a29\u9650\u3092\u8ffd\u52a0&lt;\/legend&gt;\n            &lt;input type=&#039;input&#039; x-model=&#039;entries&#039; class=&#039;border-1 border-user p-1&#039;&gt;\n            &lt;button&gt;\u8ffd\u52a0&lt;\/button&gt;\n            &lt;input type=&#039;hidden&#039; name=&#039;guard_name&#039; x-model=&#039;query.guard_name&#039;&gt;\n \n            {{-- htmx\u3067\u30d5\u30a9\u30fc\u30e0\u3092\u9001\u4fe1\u3059\u308b --}}\n            &lt;template \n              x-for=&quot;(entry, index) in entries.split(&#039;,&#039;).map(s =&gt; s.trim())&quot;\n              :key=&quot;index&quot;\n            &gt;\n              &lt;span&gt;\n                &lt;input type=&quot;hidden&quot; :name=&quot;`items[${index}][name]`&quot; :value=&quot;entry&quot;&gt;\n                &lt;input type=&quot;hidden&quot; :name=&quot;`items[${index}][guard_name]`&quot; :value=&quot;query.guard_name&quot;&gt;\n              &lt;\/span&gt;\n            &lt;\/template&gt;\n          &lt;\/fieldset&gt;\n        &lt;\/form&gt;\n      &lt;\/div&gt;  &lt;!-- end of right_colum role5,role6,role7--&gt;\n    &lt;\/div&gt;\n  &lt;\/x-feature&gt;\n@endsection\n@props([&#039;items&#039; =&gt; []])\n<\/pre>\n<\/div>\n\n\n\n<div style='display: flex; justify-content: center; gap: 4rem;\n  background-color: #ffefd5;\n  '\n>\n  <a href='laravel-06'>\u524d\u3078<\/a>\n\n<a href='.\/'>PHP\u306e\u5b66\u7fd2 \u76ee\u6b21<\/a>\n\n  <a href='laravel-08'>\u6b21\u3078<\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"\u524d\u56de\u7d42\u4e86\u6642\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9 Laravel\u3092\u4f7f\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u3057\u3066\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 $ git clone https:\/\/kiku3.tsbio.info\/git\/st [&hellip;]","protected":false},"author":2,"featured_media":0,"parent":2658,"menu_order":7,"comment_status":"closed","ping_status":"closed","template":"page-programming.php","meta":{"footnotes":""},"class_list":["post-3194","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/pages\/3194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/comments?post=3194"}],"version-history":[{"count":25,"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/pages\/3194\/revisions"}],"predecessor-version":[{"id":3458,"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/pages\/3194\/revisions\/3458"}],"up":[{"embeddable":true,"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/pages\/2658"}],"wp:attachment":[{"href":"https:\/\/biochemistry.isc.chubu.ac.jp\/labo\/suzuki\/wp-json\/wp\/v2\/media?parent=3194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}