[{"data":1,"prerenderedAt":1921},["ShallowReactive",2],{"navigation":3,"\u002Fauthorization\u002Fpolicies":307,"\u002Fauthorization\u002Fpolicies-surround":1916},{"3.x":4,"2.x":203},[5,32,61,99,121,147,165],{"title":6,"icon":7,"path":8,"stem":9,"children":10,"page":31},"Getting Started","i-heroicons-star","\u002Fgetting-started","1.getting-started",[11,15,19,23,27],{"title":12,"path":13,"stem":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction",{"title":16,"path":17,"stem":18},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":20,"path":21,"stem":22},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start",{"title":24,"path":25,"stem":26},"Configuration","\u002Fgetting-started\u002Fconfiguration","1.getting-started\u002F4.configuration",{"title":28,"path":29,"stem":30},"Upgrade guide","\u002Fgetting-started\u002Fupgrade-guide","1.getting-started\u002F5.upgrade-guide",false,{"title":33,"icon":34,"path":35,"stem":36,"children":37,"page":31},"Resources","i-heroicons-document-text","\u002Fresources","2.resources",[38,41,45,49,53,57],{"title":33,"path":39,"stem":40},"\u002Fresources\u002Fresources","2.resources\u002F1.resources",{"title":42,"path":43,"stem":44},"Fields","\u002Fresources\u002Ffields","2.resources\u002F2.fields",{"title":46,"path":47,"stem":48},"Relationships","\u002Fresources\u002Frelations","2.resources\u002F3.relations",{"title":50,"path":51,"stem":52},"Validation","\u002Fresources\u002Fvalidation","2.resources\u002F4.validation",{"title":54,"path":55,"stem":56},"Perimeter","\u002Fresources\u002Fperimeter","2.resources\u002F5.perimeter",{"title":58,"path":59,"stem":60},"Limits","\u002Fresources\u002Flimits","2.resources\u002F6.limits",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":31},"Search","i-heroicons-magnifying-glass","\u002Fsearch","3.search",[67,71,75,79,83,87,91,95],{"title":68,"path":69,"stem":70},"Search overview","\u002Fsearch\u002Foverview","3.search\u002F1.overview",{"title":72,"path":73,"stem":74},"Search filters","\u002Fsearch\u002Ffilters","3.search\u002F2.filters",{"title":76,"path":77,"stem":78},"Sorts and selects","\u002Fsearch\u002Fsorts-and-selects","3.search\u002F3.sorts-and-selects",{"title":80,"path":81,"stem":82},"Includes and aggregates","\u002Fsearch\u002Fincludes-and-aggregates","3.search\u002F4.includes-and-aggregates",{"title":84,"path":85,"stem":86},"Scopes and instructions","\u002Fsearch\u002Fscopes-and-instructions","3.search\u002F5.scopes-and-instructions",{"title":88,"path":89,"stem":90},"Text search","\u002Fsearch\u002Ftext-search","3.search\u002F6.text-search",{"title":92,"path":93,"stem":94},"Search engines","\u002Fsearch\u002Fsearch-engines","3.search\u002F7.search-engines",{"title":96,"path":97,"stem":98},"Searching outside HTTP","\u002Fsearch\u002Foutside-http","3.search\u002F8.outside-http",{"title":100,"icon":101,"path":102,"stem":103,"children":104,"page":31},"Writing","i-heroicons-pencil-square","\u002Fwriting","4.writing",[105,109,113,117],{"title":106,"path":107,"stem":108},"Mutate","\u002Fwriting\u002Fmutate","4.writing\u002F1.mutate",{"title":110,"path":111,"stem":112},"Writing relations","\u002Fwriting\u002Frelations","4.writing\u002F2.relations",{"title":114,"path":115,"stem":116},"Versioned rows","\u002Fwriting\u002Fversioned-rows","4.writing\u002F3.versioned-rows",{"title":118,"path":119,"stem":120},"Deleting and restoring","\u002Fwriting\u002Fdeleting","4.writing\u002F4.deleting",{"title":122,"icon":123,"path":124,"stem":125,"children":126,"page":31},"Actions and Metrics","i-heroicons-bolt","\u002Factions-and-metrics","5.actions-and-metrics",[127,131,135,139,143],{"title":128,"path":129,"stem":130},"Actions","\u002Factions-and-metrics\u002Factions","5.actions-and-metrics\u002F1.actions",{"title":132,"path":133,"stem":134},"Queued Actions","\u002Factions-and-metrics\u002Fqueued-actions","5.actions-and-metrics\u002F2.queued-actions",{"title":136,"path":137,"stem":138},"Confirmation","\u002Factions-and-metrics\u002Fconfirmation","5.actions-and-metrics\u002F3.confirmation",{"title":140,"path":141,"stem":142},"Metrics","\u002Factions-and-metrics\u002Fmetrics","5.actions-and-metrics\u002F4.metrics",{"title":144,"path":145,"stem":146},"Exports","\u002Factions-and-metrics\u002Fexports","5.actions-and-metrics\u002F5.exports",{"title":148,"icon":149,"path":150,"stem":151,"children":152,"page":31},"Authorization","i-heroicons-lock-closed","\u002Fauthorization","6.authorization",[153,157,161],{"title":154,"path":155,"stem":156},"Policies","\u002Fauthorization\u002Fpolicies","6.authorization\u002F1.policies",{"title":158,"path":159,"stem":160},"Gates","\u002Fauthorization\u002Fgates","6.authorization\u002F2.gates",{"title":162,"path":163,"stem":164},"Decision Cache","\u002Fauthorization\u002Fdecision-cache","6.authorization\u002F3.decision-cache",{"title":166,"icon":167,"path":168,"stem":169,"children":170,"page":31},"Digging Deeper","i-heroicons-list-bullet","\u002Fdigging-deeper","7.digging-deeper",[171,175,179,183,187,191,195,199],{"title":172,"path":173,"stem":174},"Details","\u002Fdigging-deeper\u002Fdetails","7.digging-deeper\u002F1.details",{"title":176,"path":177,"stem":178},"Events and Hooks","\u002Fdigging-deeper\u002Fevents-and-hooks","7.digging-deeper\u002F2.events-and-hooks",{"title":180,"path":181,"stem":182},"Custom Responses","\u002Fdigging-deeper\u002Fresponses","7.digging-deeper\u002F3.responses",{"title":184,"path":185,"stem":186},"OpenAPI Documentation","\u002Fdigging-deeper\u002Fopenapi","7.digging-deeper\u002F4.openapi",{"title":188,"path":189,"stem":190},"Precognition","\u002Fdigging-deeper\u002Fprecognition","7.digging-deeper\u002F5.precognition",{"title":192,"path":193,"stem":194},"Artisan Commands","\u002Fdigging-deeper\u002Fartisan","7.digging-deeper\u002F6.artisan",{"title":196,"path":197,"stem":198},"Laravel Boost Skill","\u002Fdigging-deeper\u002Fai-skill","7.digging-deeper\u002F7.ai-skill",{"title":200,"path":201,"stem":202},"Translations","\u002Fdigging-deeper\u002Ftranslations","7.digging-deeper\u002F8.translations",[204,215,237,260,297],{"title":6,"icon":7,"path":205,"stem":206,"children":207,"page":31},"\u002F2.x\u002Fgetting-started","2.x\u002F1.getting-started",[208,211],{"title":16,"path":209,"stem":210},"\u002F2.x\u002Fgetting-started\u002Finstallation","2.x\u002F1.getting-started\u002F1.installation",{"title":212,"path":213,"stem":214},"Upgrade Guide","\u002F2.x\u002Fgetting-started\u002Fupgrade-guide","2.x\u002F1.getting-started\u002F2.upgrade-guide",{"title":216,"icon":217,"path":218,"stem":219,"children":220,"page":31},"Endpoints","i-heroicons-arrow-uturn-left","\u002F2.x\u002Fendpoints","2.x\u002F2.endpoints",[221,224,227,230,233],{"title":172,"path":222,"stem":223},"\u002F2.x\u002Fendpoints\u002Fdetails","2.x\u002F2.endpoints\u002F1.details",{"title":62,"path":225,"stem":226},"\u002F2.x\u002Fendpoints\u002Fsearch","2.x\u002F2.endpoints\u002F2.search",{"title":106,"path":228,"stem":229},"\u002F2.x\u002Fendpoints\u002Fmutate","2.x\u002F2.endpoints\u002F3.mutate",{"title":128,"path":231,"stem":232},"\u002F2.x\u002Fendpoints\u002Factions","2.x\u002F2.endpoints\u002F4.actions",{"title":234,"path":235,"stem":236},"Delete","\u002F2.x\u002Fendpoints\u002Fdelete","2.x\u002F2.endpoints\u002F5.delete",{"title":33,"icon":34,"path":238,"stem":239,"children":240,"page":31},"\u002F2.x\u002Fresources","2.x\u002F3.resources",[241,245,249,252,256],{"title":242,"path":243,"stem":244},"Basics","\u002F2.x\u002Fresources\u002Fbasics","2.x\u002F3.resources\u002F1.basics",{"title":246,"path":247,"stem":248},"Exposed Data","\u002F2.x\u002Fresources\u002Fexposed-data","2.x\u002F3.resources\u002F2.exposed-data",{"title":46,"path":250,"stem":251},"\u002F2.x\u002Fresources\u002Frelationships","2.x\u002F3.resources\u002F3.relationships",{"title":253,"path":254,"stem":255},"Validations","\u002F2.x\u002Fresources\u002Fvalidations","2.x\u002F3.resources\u002F4.validations",{"title":257,"path":258,"stem":259},"Interactions","\u002F2.x\u002Fresources\u002Finteractions","2.x\u002F3.resources\u002F5.interactions",{"title":166,"icon":167,"path":261,"stem":262,"children":263,"page":31},"\u002F2.x\u002Fdigging-deeper","2.x\u002F4.digging-deeper",[264,267,271,274,278,282,286,290,294],{"title":128,"path":265,"stem":266},"\u002F2.x\u002Fdigging-deeper\u002Factions","2.x\u002F4.digging-deeper\u002F1.actions",{"title":268,"path":269,"stem":270},"Hooks","\u002F2.x\u002Fdigging-deeper\u002Fhooks","2.x\u002F4.digging-deeper\u002F2.hooks",{"title":158,"path":272,"stem":273},"\u002F2.x\u002Fdigging-deeper\u002Fgates","2.x\u002F4.digging-deeper\u002F3.gates",{"title":275,"path":276,"stem":277},"Authorizations","\u002F2.x\u002Fdigging-deeper\u002Fauthorizations","2.x\u002F4.digging-deeper\u002F4.authorizations",{"title":279,"path":280,"stem":281},"Full Text Search","\u002F2.x\u002Fdigging-deeper\u002Ffull-text-search","2.x\u002F4.digging-deeper\u002F5.full-text-search",{"title":283,"path":284,"stem":285},"Instructions","\u002F2.x\u002Fdigging-deeper\u002Finstructions","2.x\u002F4.digging-deeper\u002F6.instructions",{"title":287,"path":288,"stem":289},"Responses","\u002F2.x\u002Fdigging-deeper\u002Fresponses","2.x\u002F4.digging-deeper\u002F7.responses",{"title":291,"path":292,"stem":293},"Documentation","\u002F2.x\u002Fdigging-deeper\u002Fdocumentation","2.x\u002F4.digging-deeper\u002F8.documentation",{"title":188,"path":295,"stem":296},"\u002F2.x\u002Fdigging-deeper\u002Fprecognition","2.x\u002F4.digging-deeper\u002F9.precognition",{"title":298,"icon":299,"path":300,"stem":301,"children":302,"page":31},"Integrations","i-lucide-puzzle","\u002F2.x\u002Fintegrations","2.x\u002F5.integrations",[303],{"title":304,"path":305,"stem":306},"Flutter","\u002F2.x\u002Fintegrations\u002Fflutter","2.x\u002F5.integrations\u002F1.flutter",{"id":308,"title":154,"body":309,"description":1909,"extension":1910,"links":1911,"meta":1912,"navigation":595,"path":155,"seo":1913,"sitemap":1914,"stem":156,"__hash__":1915},"docs3x\u002F6.authorization\u002F1.policies.md",{"type":310,"value":311,"toc":1896},"minimark",[312,324,336,450,455,472,531,536,543,712,749,753,758,764,858,878,1091,1153,1157,1160,1234,1310,1319,1323,1337,1374,1378,1393,1404,1436,1446,1534,1537,1699,1724,1728,1746,1788,1792,1829,1833,1843,1877,1886,1892],[313,314,315,316,323],"p",{},"Every endpoint checks the ",[317,318,322],"a",{"href":319,"rel":320},"https:\u002F\u002Flaravel.com\u002Fdocs\u002Fauthorization#creating-policies",[321],"nofollow","Laravel policy"," of the models it touches. The checks run in two stages: the abilities of the endpoint and of every resource that the payload reaches, before validation; then the abilities of each row, before the first write.",[313,325,326,327,331,332,335],{},"Define a policy for every model you expose. ",[328,329,330],"code",{},"php artisan rest:policy PostPolicy --model=Post"," writes one that allows every ability to a signed-in user: edit it before production. See ",[317,333,334],{"href":193},"Artisan commands",".",[337,338,339,352],"table",{},[340,341,342],"thead",{},[343,344,345,349],"tr",{},[346,347,348],"th",{},"Policy method",[346,350,351],{},"Checked by",[353,354,355,366,394,407,419,442],"tbody",{},[343,356,357,363],{},[358,359,360],"td",{},[328,361,362],{},"viewAny",[358,364,365],{},"every endpoint of the resource, and every resource that a payload reaches",[343,367,368,373],{},[358,369,370],{},[328,371,372],{},"view",[358,374,375,376,379,380,379,383,386,387,390,391,393],{},"the targets of ",[328,377,378],{},"attach",", ",[328,381,382],{},"detach",[328,384,385],{},"sync"," and ",[328,388,389],{},"toggle",", and the ",[328,392,372],{}," gate",[343,395,396,401],{},[358,397,398],{},[328,399,400],{},"create",[358,402,403,406],{},[328,404,405],{},"mutate"," creations: once per resource class, then once per created row",[343,408,409,414],{},[358,410,411],{},[328,412,413],{},"update",[358,415,416,418],{},[328,417,405],{}," updates, with the changes of the entry, and links checked on the parent row when the relation declares no ability",[343,420,421,432],{},[358,422,423,379,426,379,429],{},[328,424,425],{},"delete",[328,427,428],{},"restore",[328,430,431],{},"forceDelete",[358,433,434,379,437,379,439],{},[328,435,436],{},"destroy",[328,438,428],{},[328,440,441],{},"forceDestroy",[343,443,444,447],{},[358,445,446],{},"the abilities that a relation declares",[358,448,449],{},"the links of that relation",[451,452,454],"h2",{"id":453},"checks-before-validation","Checks before validation",[313,456,457,458,461,462,464,465,468,469,471],{},"Each request checks the abilities of its endpoint, then the resources that its payload reaches, before it validates the payload and before any query. A denied check answers with the status of the policy's response, ",[328,459,460],{},"403"," by default, even when the payload is invalid: the ",[328,463,460],{}," comes before the ",[328,466,467],{},"422",", also for ",[317,470,188],{"href":189}," requests.",[473,474,475,499,512,524],"ul",{},[476,477,478,379,481,379,484,379,486,379,488,386,490,492,493,495,496,335],"li",{},[328,479,480],{},"details",[328,482,483],{},"search",[328,485,405],{},[328,487,436],{},[328,489,428],{},[328,491,441],{}," check ",[328,494,362],{}," on their resource. Actions and metrics add their own abilities, see ",[317,497,128],{"href":498},"\u002Factions-and-metrics\u002Factions#abilities",[476,500,501,502,504,505,390,508,511],{},"Every resource that the payload reaches needs ",[328,503,362],{},": each level of an include, of an aggregate and of a relation filter, the relation of a sort such as ",[328,506,507],{},"author.last_name",[328,509,510],{},"response"," block of a mutation.",[476,513,514,515,517,518,520,521,523],{},"Each ",[328,516,400],{}," in ",[328,519,405],{},", at the root or under a relation, needs ",[328,522,400],{}," on the created resource, checked once per resource class with the model class.",[476,525,526,527,530],{},"The ",[328,528,529],{},"authorize()"," method of a request still runs first.",[532,533,535],"h3",{"id":534},"changing-the-abilities-of-an-endpoint","Changing the abilities of an endpoint",[313,537,538,539,542],{},"Override ",[328,540,541],{},"abilities()"," on the resource. The list replaces the default of the endpoint:",[544,545,550],"pre",{"className":546,"code":547,"language":548,"meta":549,"style":549},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use Lomkit\\Rest\\Http\\Routing\\Endpoint;\n\npublic function abilities(Endpoint $endpoint): array\n{\n    return $endpoint === Endpoint::Destroy ? ['viewAny', 'deleteAny'] : parent::abilities($endpoint);\n}\n","php","",[328,551,552,590,597,629,635,706],{"__ignoreMap":549},[553,554,557,561,565,569,572,574,577,579,582,584,587],"span",{"class":555,"line":556},"line",1,[553,558,560],{"class":559},"sbssI","use",[553,562,564],{"class":563},"sTEyZ"," Lomkit",[553,566,568],{"class":567},"sMK4o","\\",[553,570,571],{"class":563},"Rest",[553,573,568],{"class":567},[553,575,576],{"class":563},"Http",[553,578,568],{"class":567},[553,580,581],{"class":563},"Routing",[553,583,568],{"class":567},[553,585,586],{"class":563},"Endpoint",[553,588,589],{"class":567},";\n",[553,591,593],{"class":555,"line":592},2,[553,594,596],{"emptyLinePlaceholder":595},true,"\n",[553,598,600,604,607,611,614,617,620,623,626],{"class":555,"line":599},3,[553,601,603],{"class":602},"spNyl","public",[553,605,606],{"class":602}," function",[553,608,610],{"class":609},"s2Zo4"," abilities",[553,612,613],{"class":567},"(",[553,615,586],{"class":616},"sBMFI",[553,618,619],{"class":567}," $",[553,621,622],{"class":563},"endpoint",[553,624,625],{"class":567},"):",[553,627,628],{"class":559}," array\n",[553,630,632],{"class":555,"line":631},4,[553,633,634],{"class":567},"{\n",[553,636,638,642,644,647,650,653,656,659,662,665,668,671,673,676,679,682,684,687,690,693,695,698,701,703],{"class":555,"line":637},5,[553,639,641],{"class":640},"s7zQu","    return",[553,643,619],{"class":567},[553,645,646],{"class":563},"endpoint ",[553,648,649],{"class":567},"===",[553,651,652],{"class":616}," Endpoint",[553,654,655],{"class":567},"::",[553,657,658],{"class":563},"Destroy ",[553,660,661],{"class":567},"?",[553,663,664],{"class":567}," [",[553,666,667],{"class":567},"'",[553,669,362],{"class":670},"sfazB",[553,672,667],{"class":567},[553,674,675],{"class":567},",",[553,677,678],{"class":567}," '",[553,680,681],{"class":670},"deleteAny",[553,683,667],{"class":567},[553,685,686],{"class":567},"]",[553,688,689],{"class":567}," :",[553,691,692],{"class":602}," parent",[553,694,655],{"class":567},[553,696,697],{"class":609},"abilities",[553,699,700],{"class":567},"($",[553,702,622],{"class":563},[553,704,705],{"class":567},");\n",[553,707,709],{"class":555,"line":708},6,[553,710,711],{"class":567},"}\n",[473,713,714,731,742],{},[476,715,716,717,719,720,723,724,727,728,730],{},"Keep ",[328,718,362],{}," in the list to add an ability: a resource that returns ",[328,721,722],{},"['export']"," for ",[328,725,726],{},"Endpoint::Search"," no longer checks ",[328,729,362],{}," there.",[476,732,733,386,736,739,740,335],{},[328,734,735],{},"Endpoint::Operate",[328,737,738],{},"Endpoint::Metric"," are the exception: their list adds to ",[328,741,362],{},[476,743,744,745,748],{},"To let users write a resource that they cannot list, return ",[328,746,747],{},"[]"," for the write endpoints.",[451,750,752],{"id":751},"row-checks","Row checks",[313,754,755,757],{},[328,756,405],{}," checks every row of the request in one batch, inside its transaction, before the first write: a denied row writes nothing, and no hook, event or model observer runs.",[313,759,760,761,763],{},"Each created row is checked with ",[328,762,400],{}," and its draft: an unsaved model filled with the validated attributes of its entry and with the keys that its relations set. Declare the draft as an optional parameter:",[544,765,767],{"className":546,"code":766,"language":548,"meta":549,"style":549},"public function create(User $user, ?Post $draft = null): bool\n{\n    return $draft === null || $draft->team_id === $user->team_id;\n}\n",[328,768,769,810,814,854],{"__ignoreMap":549},[553,770,771,773,775,778,780,783,785,788,790,793,796,798,801,804,807],{"class":555,"line":556},[553,772,603],{"class":602},[553,774,606],{"class":602},[553,776,777],{"class":609}," create",[553,779,613],{"class":567},[553,781,782],{"class":616},"User",[553,784,619],{"class":567},[553,786,787],{"class":563},"user",[553,789,675],{"class":567},[553,791,792],{"class":567}," ?",[553,794,795],{"class":616},"Post",[553,797,619],{"class":567},[553,799,800],{"class":563},"draft ",[553,802,803],{"class":567},"=",[553,805,806],{"class":567}," null):",[553,808,809],{"class":559}," bool\n",[553,811,812],{"class":555,"line":592},[553,813,634],{"class":567},[553,815,816,818,820,822,824,827,830,832,835,838,841,843,845,847,849,852],{"class":555,"line":599},[553,817,641],{"class":640},[553,819,619],{"class":567},[553,821,800],{"class":563},[553,823,649],{"class":567},[553,825,826],{"class":567}," null",[553,828,829],{"class":567}," ||",[553,831,619],{"class":567},[553,833,834],{"class":563},"draft",[553,836,837],{"class":567},"->",[553,839,840],{"class":563},"team_id ",[553,842,649],{"class":567},[553,844,619],{"class":567},[553,846,787],{"class":563},[553,848,837],{"class":567},[553,850,851],{"class":563},"team_id",[553,853,589],{"class":567},[553,855,856],{"class":555,"line":631},[553,857,711],{"class":567},[313,859,860,861,863,864,867,868,379,871,386,874,877],{},"Each updated row is checked with ",[328,862,413],{},", the stored row and a ",[328,865,866],{},"Lomkit\\Rest\\Authorization\\Changes"," object of the values that the write sets. ",[328,869,870],{},"has($key)",[328,872,873],{},"get($key)",[328,875,876],{},"keys()"," read it:",[544,879,881],{"className":546,"code":880,"language":548,"meta":549,"style":549},"use Illuminate\\Auth\\Access\\Response;\nuse Lomkit\\Rest\\Authorization\\Changes;\n\npublic function update(User $user, Post $post, ?Changes $changes = null): Response\n{\n    return $changes?->get('team_id') !== null && $changes->get('team_id') !== $user->team_id\n        ? Response::deny('Posts cannot move to another team.')\n        : Response::allow();\n}\n",[328,882,883,907,928,932,977,981,1044,1070,1086],{"__ignoreMap":549},[553,884,885,887,890,892,895,897,900,902,905],{"class":555,"line":556},[553,886,560],{"class":559},[553,888,889],{"class":563}," Illuminate",[553,891,568],{"class":567},[553,893,894],{"class":563},"Auth",[553,896,568],{"class":567},[553,898,899],{"class":563},"Access",[553,901,568],{"class":567},[553,903,904],{"class":563},"Response",[553,906,589],{"class":567},[553,908,909,911,913,915,917,919,921,923,926],{"class":555,"line":592},[553,910,560],{"class":559},[553,912,564],{"class":563},[553,914,568],{"class":567},[553,916,571],{"class":563},[553,918,568],{"class":567},[553,920,148],{"class":563},[553,922,568],{"class":567},[553,924,925],{"class":563},"Changes",[553,927,589],{"class":567},[553,929,930],{"class":555,"line":599},[553,931,596],{"emptyLinePlaceholder":595},[553,933,934,936,938,941,943,945,947,949,951,954,956,959,961,963,965,967,970,972,974],{"class":555,"line":631},[553,935,603],{"class":602},[553,937,606],{"class":602},[553,939,940],{"class":609}," update",[553,942,613],{"class":567},[553,944,782],{"class":616},[553,946,619],{"class":567},[553,948,787],{"class":563},[553,950,675],{"class":567},[553,952,953],{"class":616}," Post",[553,955,619],{"class":567},[553,957,958],{"class":563},"post",[553,960,675],{"class":567},[553,962,792],{"class":567},[553,964,925],{"class":616},[553,966,619],{"class":567},[553,968,969],{"class":563},"changes ",[553,971,803],{"class":567},[553,973,806],{"class":567},[553,975,976],{"class":616}," Response\n",[553,978,979],{"class":555,"line":637},[553,980,634],{"class":567},[553,982,983,985,987,990,993,996,998,1000,1002,1004,1007,1010,1012,1015,1017,1019,1021,1023,1025,1027,1029,1031,1033,1035,1037,1039,1041],{"class":555,"line":708},[553,984,641],{"class":640},[553,986,619],{"class":567},[553,988,989],{"class":563},"changes",[553,991,992],{"class":567},"?->",[553,994,995],{"class":609},"get",[553,997,613],{"class":567},[553,999,667],{"class":567},[553,1001,851],{"class":670},[553,1003,667],{"class":567},[553,1005,1006],{"class":567},")",[553,1008,1009],{"class":567}," !==",[553,1011,826],{"class":567},[553,1013,1014],{"class":567}," &&",[553,1016,619],{"class":567},[553,1018,989],{"class":563},[553,1020,837],{"class":567},[553,1022,995],{"class":609},[553,1024,613],{"class":567},[553,1026,667],{"class":567},[553,1028,851],{"class":670},[553,1030,667],{"class":567},[553,1032,1006],{"class":567},[553,1034,1009],{"class":567},[553,1036,619],{"class":567},[553,1038,787],{"class":563},[553,1040,837],{"class":567},[553,1042,1043],{"class":563},"team_id\n",[553,1045,1047,1050,1053,1055,1058,1060,1062,1065,1067],{"class":555,"line":1046},7,[553,1048,1049],{"class":567},"        ?",[553,1051,1052],{"class":616}," Response",[553,1054,655],{"class":567},[553,1056,1057],{"class":609},"deny",[553,1059,613],{"class":567},[553,1061,667],{"class":567},[553,1063,1064],{"class":670},"Posts cannot move to another team.",[553,1066,667],{"class":567},[553,1068,1069],{"class":567},")\n",[553,1071,1073,1076,1078,1080,1083],{"class":555,"line":1072},8,[553,1074,1075],{"class":567},"        :",[553,1077,1052],{"class":616},[553,1079,655],{"class":567},[553,1081,1082],{"class":609},"allow",[553,1084,1085],{"class":567},"();\n",[553,1087,1089],{"class":555,"line":1088},9,[553,1090,711],{"class":567},[473,1092,1093,1109,1135,1138],{},[476,1094,1095,1096,1098,1099,1098,1101,1103,1104,1106,1107,335],{},"A row that an entry names without writing it, the target of an ",[328,1097,378],{},", a ",[328,1100,382],{},[328,1102,385],{}," or a ",[328,1105,389],{}," without attributes, is checked with ",[328,1108,372],{},[476,1110,1111,1112,379,1115,379,1118,379,1121,379,1124,1127,1128,1131,1132,1134],{},"A row that an entry moves under a ",[328,1113,1114],{},"HasOne",[328,1116,1117],{},"HasOneOfMany",[328,1119,1120],{},"HasMany",[328,1122,1123],{},"MorphOne",[328,1125,1126],{},"MorphOneOfMany"," or ",[328,1129,1130],{},"MorphMany"," relation is checked with ",[328,1133,413],{}," and its new keys.",[476,1136,1137],{},"The policies see the rows as they were before the request.",[476,1139,1140,379,1142,386,1144,492,1146,379,1148,1127,1150,1152],{},[328,1141,436],{},[328,1143,428],{},[328,1145,441],{},[328,1147,425],{},[328,1149,428],{},[328,1151,431],{}," on every row before they write any row.",[532,1154,1156],{"id":1155},"relation-links","Relation links",[313,1158,1159],{},"A relation declares the abilities that check its links, on the policy of the parent row, with the parent and the related row:",[544,1161,1163],{"className":546,"code":1162,"language":548,"meta":549,"style":549},"BelongsToMany::make('tags', TagResource::class)\n    ->abilities(attach: 'attachTag', detach: 'detachTag'),\n",[328,1164,1165,1196],{"__ignoreMap":549},[553,1166,1167,1170,1172,1175,1177,1179,1182,1184,1186,1189,1191,1194],{"class":555,"line":556},[553,1168,1169],{"class":616},"BelongsToMany",[553,1171,655],{"class":567},[553,1173,1174],{"class":609},"make",[553,1176,613],{"class":567},[553,1178,667],{"class":567},[553,1180,1181],{"class":670},"tags",[553,1183,667],{"class":567},[553,1185,675],{"class":567},[553,1187,1188],{"class":616}," TagResource",[553,1190,655],{"class":567},[553,1192,1193],{"class":559},"class",[553,1195,1069],{"class":567},[553,1197,1198,1201,1203,1205,1207,1210,1212,1215,1217,1219,1222,1224,1226,1229,1231],{"class":555,"line":592},[553,1199,1200],{"class":567},"    ->",[553,1202,697],{"class":609},[553,1204,613],{"class":567},[553,1206,378],{"class":616},[553,1208,1209],{"class":567},":",[553,1211,678],{"class":567},[553,1213,1214],{"class":670},"attachTag",[553,1216,667],{"class":567},[553,1218,675],{"class":567},[553,1220,1221],{"class":616}," detach",[553,1223,1209],{"class":567},[553,1225,678],{"class":567},[553,1227,1228],{"class":670},"detachTag",[553,1230,667],{"class":567},[553,1232,1233],{"class":567},"),\n",[544,1235,1237],{"className":546,"code":1236,"language":548,"meta":549,"style":549},"public function attachTag(User $user, Post $post, Tag $tag): bool\n{\n    return $user->team_id === $post->team_id;\n}\n",[328,1238,1239,1278,1282,1306],{"__ignoreMap":549},[553,1240,1241,1243,1245,1248,1250,1252,1254,1256,1258,1260,1262,1264,1266,1269,1271,1274,1276],{"class":555,"line":556},[553,1242,603],{"class":602},[553,1244,606],{"class":602},[553,1246,1247],{"class":609}," attachTag",[553,1249,613],{"class":567},[553,1251,782],{"class":616},[553,1253,619],{"class":567},[553,1255,787],{"class":563},[553,1257,675],{"class":567},[553,1259,953],{"class":616},[553,1261,619],{"class":567},[553,1263,958],{"class":563},[553,1265,675],{"class":567},[553,1267,1268],{"class":616}," Tag",[553,1270,619],{"class":567},[553,1272,1273],{"class":563},"tag",[553,1275,625],{"class":567},[553,1277,809],{"class":559},[553,1279,1280],{"class":555,"line":592},[553,1281,634],{"class":567},[553,1283,1284,1286,1288,1290,1292,1294,1296,1298,1300,1302,1304],{"class":555,"line":599},[553,1285,641],{"class":640},[553,1287,619],{"class":567},[553,1289,787],{"class":563},[553,1291,837],{"class":567},[553,1293,840],{"class":563},[553,1295,649],{"class":567},[553,1297,619],{"class":567},[553,1299,958],{"class":563},[553,1301,837],{"class":567},[553,1303,851],{"class":563},[553,1305,589],{"class":567},[553,1307,1308],{"class":555,"line":631},[553,1309,711],{"class":567},[313,1311,1312,1313,1315,1316,335],{},"Without a declared ability, the link is checked with ",[328,1314,413],{}," on the parent row. A declared ability that no policy method answers is denied. See ",[317,1317,1318],{"href":47},"Relations",[451,1320,1322],{"id":1321},"the-perimeter-and-the-policies","The perimeter and the policies",[313,1324,1325,1330,1331,1333,1334,1336],{},[317,1326,1327],{"href":55},[328,1328,1329],{},"perimeterQuery()"," decides which rows exist for the client: a key outside it is a ",[328,1332,467],{},", as if the row did not exist. A policy decides what the client may do with a row it can see: a refused row is a ",[328,1335,460],{},". Use the perimeter for tenants and visibility, and the policies for rights.",[473,1338,1339,1352],{},[476,1340,1341,1342,1348,1349,1351],{},"A request that names keys outside the perimeter dispatches the ",[317,1343,1345],{"href":1344},"\u002Fdigging-deeper\u002Fevents-and-hooks#keys-out-of-reach",[328,1346,1347],{},"KeysOutOfReach"," event before its ",[328,1350,467],{},", so that a listener can record it.",[476,1353,1354,1360,1361,1363,1364,1367,1368,1370,1371,335],{},[317,1355,1357],{"href":1356},"\u002Fdigging-deeper\u002Fartisan#checking-the-application",[328,1358,1359],{},"php artisan rest:check"," reports each resource that the routes reach without its own ",[328,1362,1329],{},", and each action on rows without ",[328,1365,1366],{},"authorizeEach()",". Mark a resource whose rows are meant for every user who passes ",[328,1369,362],{},", such as countries, with ",[328,1372,1373],{},"#[Lomkit\\Rest\\Attributes\\WithoutPerimeter]",[451,1375,1377],{"id":1376},"denials","Denials",[313,1379,1380,1381,1384,1385,1388,1389,1392],{},"A denied check throws ",[328,1382,1383],{},"Lomkit\\Rest\\Exceptions\\AuthorizationDenied",", which extends Laravel's ",[328,1386,1387],{},"AuthorizationException",". It holds every denial of the batch, at most 50, in ",[328,1390,1391],{},"$exception->denials",": the path in the payload, the ability, the resource class, the key of the row and the message.",[313,1394,1395,1396,1399,1400,1403],{},"The response takes the message and the status of the first denial, in the order of the request, so ",[328,1397,1398],{},"Response::denyAsNotFound()"," still answers ",[328,1401,1402],{},"404",". The body holds the message only:",[544,1405,1409],{"className":1406,"code":1407,"language":1408,"meta":549,"style":549},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\"message\": \"Teams are not listed.\"}\n","json",[328,1410,1411],{"__ignoreMap":549},[553,1412,1413,1416,1419,1422,1424,1426,1429,1432,1434],{"class":555,"line":556},[553,1414,1415],{"class":567},"{",[553,1417,1418],{"class":567},"\"",[553,1420,1421],{"class":602},"message",[553,1423,1418],{"class":567},[553,1425,1209],{"class":567},[553,1427,1428],{"class":567}," \"",[553,1430,1431],{"class":670},"Teams are not listed.",[553,1433,1418],{"class":567},[553,1435,711],{"class":567},[313,1437,1438,1439,1442,1443,1209],{},"A denial without a message gives ",[328,1440,1441],{},"This action is unauthorized.",", as in Laravel. To add the denials to the body, register the renderer in ",[328,1444,1445],{},"bootstrap\u002Fapp.php",[544,1447,1449],{"className":546,"code":1448,"language":548,"meta":549,"style":549},"use Lomkit\\Rest\\Exceptions\\DenialsRenderer;\n\n->withExceptions(function (Exceptions $exceptions): void {\n    $exceptions->render(new DenialsRenderer);\n})\n",[328,1450,1451,1473,1477,1507,1529],{"__ignoreMap":549},[553,1452,1453,1455,1457,1459,1461,1463,1466,1468,1471],{"class":555,"line":556},[553,1454,560],{"class":559},[553,1456,564],{"class":563},[553,1458,568],{"class":567},[553,1460,571],{"class":563},[553,1462,568],{"class":567},[553,1464,1465],{"class":563},"Exceptions",[553,1467,568],{"class":567},[553,1469,1470],{"class":563},"DenialsRenderer",[553,1472,589],{"class":567},[553,1474,1475],{"class":555,"line":592},[553,1476,596],{"emptyLinePlaceholder":595},[553,1478,1479,1481,1484,1486,1489,1492,1494,1496,1499,1501,1504],{"class":555,"line":599},[553,1480,837],{"class":567},[553,1482,1483],{"class":609},"withExceptions",[553,1485,613],{"class":567},[553,1487,1488],{"class":602},"function",[553,1490,1491],{"class":567}," (",[553,1493,1465],{"class":616},[553,1495,619],{"class":567},[553,1497,1498],{"class":563},"exceptions",[553,1500,625],{"class":567},[553,1502,1503],{"class":559}," void",[553,1505,1506],{"class":567}," {\n",[553,1508,1509,1512,1514,1516,1519,1521,1524,1527],{"class":555,"line":631},[553,1510,1511],{"class":567},"    $",[553,1513,1498],{"class":563},[553,1515,837],{"class":567},[553,1517,1518],{"class":609},"render",[553,1520,613],{"class":567},[553,1522,1523],{"class":559},"new",[553,1525,1526],{"class":616}," DenialsRenderer",[553,1528,705],{"class":567},[553,1530,1531],{"class":555,"line":637},[553,1532,1533],{"class":567},"})\n",[313,1535,1536],{},"The body then lists every denial. For a search whose aggregate and include reach two resources that the user cannot list:",[544,1538,1540],{"className":1406,"code":1539,"language":1408,"meta":549,"style":549},"{\n  \"message\": \"Tags are not listed.\",\n  \"denials\": [\n    {\"path\": \"search.aggregates.0\", \"ability\": \"viewAny\", \"message\": \"Tags are not listed.\"},\n    {\"path\": \"search.includes.0\", \"ability\": \"viewAny\", \"message\": \"Teams are not listed.\"}\n  ]\n}\n",[328,1541,1542,1546,1567,1580,1637,1690,1695],{"__ignoreMap":549},[553,1543,1544],{"class":555,"line":556},[553,1545,634],{"class":567},[553,1547,1548,1551,1553,1555,1557,1559,1562,1564],{"class":555,"line":592},[553,1549,1550],{"class":567},"  \"",[553,1552,1421],{"class":602},[553,1554,1418],{"class":567},[553,1556,1209],{"class":567},[553,1558,1428],{"class":567},[553,1560,1561],{"class":670},"Tags are not listed.",[553,1563,1418],{"class":567},[553,1565,1566],{"class":567},",\n",[553,1568,1569,1571,1573,1575,1577],{"class":555,"line":599},[553,1570,1550],{"class":567},[553,1572,1376],{"class":602},[553,1574,1418],{"class":567},[553,1576,1209],{"class":567},[553,1578,1579],{"class":567}," [\n",[553,1581,1582,1585,1587,1590,1592,1594,1596,1599,1601,1603,1605,1608,1610,1612,1614,1616,1618,1620,1622,1624,1626,1628,1630,1632,1634],{"class":555,"line":631},[553,1583,1584],{"class":567},"    {",[553,1586,1418],{"class":567},[553,1588,1589],{"class":616},"path",[553,1591,1418],{"class":567},[553,1593,1209],{"class":567},[553,1595,1428],{"class":567},[553,1597,1598],{"class":670},"search.aggregates.0",[553,1600,1418],{"class":567},[553,1602,675],{"class":567},[553,1604,1428],{"class":567},[553,1606,1607],{"class":616},"ability",[553,1609,1418],{"class":567},[553,1611,1209],{"class":567},[553,1613,1428],{"class":567},[553,1615,362],{"class":670},[553,1617,1418],{"class":567},[553,1619,675],{"class":567},[553,1621,1428],{"class":567},[553,1623,1421],{"class":616},[553,1625,1418],{"class":567},[553,1627,1209],{"class":567},[553,1629,1428],{"class":567},[553,1631,1561],{"class":670},[553,1633,1418],{"class":567},[553,1635,1636],{"class":567},"},\n",[553,1638,1639,1641,1643,1645,1647,1649,1651,1654,1656,1658,1660,1662,1664,1666,1668,1670,1672,1674,1676,1678,1680,1682,1684,1686,1688],{"class":555,"line":637},[553,1640,1584],{"class":567},[553,1642,1418],{"class":567},[553,1644,1589],{"class":616},[553,1646,1418],{"class":567},[553,1648,1209],{"class":567},[553,1650,1428],{"class":567},[553,1652,1653],{"class":670},"search.includes.0",[553,1655,1418],{"class":567},[553,1657,675],{"class":567},[553,1659,1428],{"class":567},[553,1661,1607],{"class":616},[553,1663,1418],{"class":567},[553,1665,1209],{"class":567},[553,1667,1428],{"class":567},[553,1669,362],{"class":670},[553,1671,1418],{"class":567},[553,1673,675],{"class":567},[553,1675,1428],{"class":567},[553,1677,1421],{"class":616},[553,1679,1418],{"class":567},[553,1681,1209],{"class":567},[553,1683,1428],{"class":567},[553,1685,1431],{"class":670},[553,1687,1418],{"class":567},[553,1689,711],{"class":567},[553,1691,1692],{"class":555,"line":708},[553,1693,1694],{"class":567},"  ]\n",[553,1696,1697],{"class":555,"line":1046},[553,1698,711],{"class":567},[473,1700,1701,1709,1718],{},[476,1702,1703,1705,1706,1708],{},[328,1704,1589],{}," is empty for the ability of the endpoint, such as ",[328,1707,362],{}," on a search.",[476,1710,1711,1714,1715,335],{},[328,1712,1713],{},"key"," appears for a check on a row: ",[328,1716,1717],{},"{\"path\": \"mutate.0\", \"ability\": \"update\", \"key\": 2, \"message\": \"Closed tickets are read-only.\"}",[476,1719,1720,1721,1723],{},"A ",[328,1722,1402],{}," stays unchanged.",[451,1725,1727],{"id":1726},"strict-mode","Strict mode",[313,1729,1730,1731,1733,1734,1737,1738,1741,1742,1745],{},"The queries check ",[328,1732,362],{}," again on each resource they search, and reuse the decisions made before validation. With ",[328,1735,1736],{},"authorizations.strict"," set to ",[328,1739,1740],{},"true",", a check that the request did not make before validation throws ",[328,1743,1744],{},"Lomkit\\Rest\\Exceptions\\UnplannedCheckException"," instead. Turn it on in your test suite to find a resource that a request reaches without a check:",[544,1747,1751],{"className":1748,"code":1749,"language":1750,"meta":549,"style":549},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cenv name=\"REST_AUTHORIZATIONS_STRICT\" value=\"true\"\u002F>\n","xml",[328,1752,1753],{"__ignoreMap":549},[553,1754,1755,1758,1762,1765,1767,1769,1772,1774,1777,1779,1781,1783,1785],{"class":555,"line":556},[553,1756,1757],{"class":567},"\u003C",[553,1759,1761],{"class":1760},"swJcz","env",[553,1763,1764],{"class":602}," name",[553,1766,803],{"class":567},[553,1768,1418],{"class":567},[553,1770,1771],{"class":670},"REST_AUTHORIZATIONS_STRICT",[553,1773,1418],{"class":567},[553,1775,1776],{"class":602}," value",[553,1778,803],{"class":567},[553,1780,1418],{"class":567},[553,1782,1740],{"class":670},[553,1784,1418],{"class":567},[553,1786,1787],{"class":567},"\u002F>\n",[451,1789,1791],{"id":1790},"within-a-request","Within a request",[473,1793,1794,1801,1815,1822],{},[476,1795,1796,1797,1800],{},"Each distinct check runs once per request: the policy runs on the first check, and the later checks reuse its decision. ",[328,1798,1799],{},"GateEvaluated"," listeners see one evaluation per distinct check.",[476,1802,1803,1804,1807,1808,386,1811,1814],{},"Policies run with ",[328,1805,1806],{},"Gate::forUser($request->user())",". ",[328,1809,1810],{},"Gate::before()",[328,1812,1813],{},"Gate::after()"," callbacks receive that user.",[476,1816,1817,1818,1821],{},"After each write, the package drops the decisions on the written model. A hook of yours that writes a model calls ",[328,1819,1820],{},"$this->request()->context()->authorizer()->forget($model)"," after the write.",[476,1823,1824,1825,1828],{},"An override of ",[328,1826,1827],{},"authorizedTo()"," on the resource applies to every check: the endpoint abilities, the reached resources, the row checks and the gates.",[451,1830,1832],{"id":1831},"turning-the-policies-off","Turning the policies off",[313,1834,538,1835,1838,1839,1842],{},[328,1836,1837],{},"isAuthorizingEnabled()"," on one resource, or on the base resource for every resource, and return ",[328,1840,1841],{},"false",". Every check then passes.",[544,1844,1846],{"className":546,"code":1845,"language":548,"meta":549,"style":549},"public function isAuthorizingEnabled(): bool\n{\n    return false;\n}\n",[328,1847,1848,1862,1866,1873],{"__ignoreMap":549},[553,1849,1850,1852,1854,1857,1860],{"class":555,"line":556},[553,1851,603],{"class":602},[553,1853,606],{"class":602},[553,1855,1856],{"class":609}," isAuthorizingEnabled",[553,1858,1859],{"class":567},"():",[553,1861,809],{"class":559},[553,1863,1864],{"class":555,"line":592},[553,1865,634],{"class":567},[553,1867,1868,1870],{"class":555,"line":599},[553,1869,641],{"class":640},[553,1871,1872],{"class":567}," false;\n",[553,1874,1875],{"class":555,"line":631},[553,1876,711],{"class":567},[1878,1879,1880],"warning",{},[313,1881,1882,1883,1885],{},"Write the policies instead whenever you can: the package expects every policy to run, ",[328,1884,362],{}," included.",[313,1887,1888,1889,335],{},"To keep decisions between requests, see ",[317,1890,1891],{"href":163},"Decision cache",[1893,1894,1895],"style",{},"html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":549,"searchDepth":556,"depth":592,"links":1897},[1898,1901,1904,1905,1906,1907,1908],{"id":453,"depth":592,"text":454,"children":1899},[1900],{"id":534,"depth":599,"text":535},{"id":751,"depth":592,"text":752,"children":1902},[1903],{"id":1155,"depth":599,"text":1156},{"id":1321,"depth":592,"text":1322},{"id":1376,"depth":592,"text":1377},{"id":1726,"depth":592,"text":1727},{"id":1790,"depth":592,"text":1791},{"id":1831,"depth":592,"text":1832},"How Laravel policies guard each endpoint, each resource a request reaches and each row it writes, before validation and before any query.","md",null,{},{"title":154,"description":1909},{"loc":155},"ohgkT23b4YKqRVI-CqaQ5jA71AH61OfXhAaBlIOLlB0",[1917,1919],{"title":144,"path":145,"stem":146,"description":1918,"children":-1},"Export the rows of a search to a CSV file in the background, in the columns the client picks, with a queued, batched action.",{"title":158,"path":159,"stem":160,"description":1920,"children":-1},"Tell clients what the user may do with each row of a search, with the answers and messages of your policies, and your own gates.",1794181350651]