[{"data":1,"prerenderedAt":1639},["ShallowReactive",2],{"navigation":3,"\u002Fresources\u002Fperimeter":307,"\u002Fresources\u002Fperimeter-surround":1634},{"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":54,"body":309,"description":1627,"extension":1628,"links":1629,"meta":1630,"navigation":377,"path":55,"seo":1631,"sitemap":1632,"stem":56,"__hash__":1633},"docs3x\u002F2.resources\u002F5.perimeter.md",{"type":310,"value":311,"toc":1612},"minimark",[312,317,325,473,508,513,526,616,624,632,653,657,660,777,781,784,859,866,870,877,955,978,982,1013,1017,1038,1042,1045,1216,1222,1226,1237,1332,1339,1343,1352,1586,1594,1598,1605,1608],[313,314,316],"h2",{"id":315},"the-perimeter-of-a-resource","The perimeter of a resource",[318,319,320,324],"p",{},[321,322,323],"code",{},"perimeterQuery()"," sets the rows of a resource that exist for the client of the request. Rows outside it are never returned, never written and never deleted: for the client, they do not exist.",[326,327,332],"pre",{"className":328,"code":329,"language":330,"meta":331,"style":331},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use Illuminate\\Contracts\\Database\\Eloquent\\Builder;\n\npublic function perimeterQuery(Builder $query): Builder\n{\n    return $query->where('team_id', $this->request()->user()->team_id);\n}\n","php","",[321,333,334,372,379,411,417,467],{"__ignoreMap":331},[335,336,339,343,347,351,354,356,359,361,364,366,369],"span",{"class":337,"line":338},"line",1,[335,340,342],{"class":341},"sbssI","use",[335,344,346],{"class":345},"sTEyZ"," Illuminate",[335,348,350],{"class":349},"sMK4o","\\",[335,352,353],{"class":345},"Contracts",[335,355,350],{"class":349},[335,357,358],{"class":345},"Database",[335,360,350],{"class":349},[335,362,363],{"class":345},"Eloquent",[335,365,350],{"class":349},[335,367,368],{"class":345},"Builder",[335,370,371],{"class":349},";\n",[335,373,375],{"class":337,"line":374},2,[335,376,378],{"emptyLinePlaceholder":377},true,"\n",[335,380,382,386,389,393,396,399,402,405,408],{"class":337,"line":381},3,[335,383,385],{"class":384},"spNyl","public",[335,387,388],{"class":384}," function",[335,390,392],{"class":391},"s2Zo4"," perimeterQuery",[335,394,395],{"class":349},"(",[335,397,368],{"class":398},"sBMFI",[335,400,401],{"class":349}," $",[335,403,404],{"class":345},"query",[335,406,407],{"class":349},"):",[335,409,410],{"class":398}," Builder\n",[335,412,414],{"class":337,"line":413},4,[335,415,416],{"class":349},"{\n",[335,418,420,424,426,428,431,434,436,439,443,445,448,451,454,457,460,462,464],{"class":337,"line":419},5,[335,421,423],{"class":422},"s7zQu","    return",[335,425,401],{"class":349},[335,427,404],{"class":345},[335,429,430],{"class":349},"->",[335,432,433],{"class":391},"where",[335,435,395],{"class":349},[335,437,438],{"class":349},"'",[335,440,442],{"class":441},"sfazB","team_id",[335,444,438],{"class":349},[335,446,447],{"class":349},",",[335,449,450],{"class":349}," $this->",[335,452,453],{"class":391},"request",[335,455,456],{"class":349},"()->",[335,458,459],{"class":391},"user",[335,461,456],{"class":349},[335,463,442],{"class":345},[335,465,466],{"class":349},");\n",[335,468,470],{"class":337,"line":469},6,[335,471,472],{"class":349},"}\n",[474,475,476,488,498,501],"ul",{},[477,478,479,480,483,484,487],"li",{},"Apply the constraints to ",[321,481,482],{},"$query"," itself and return it. The package ignores the returned builder, but an override that returns nothing throws a ",[321,485,486],{},"TypeError",".",[477,489,490,491,494,495,487],{},"Read the request with ",[321,492,493],{},"$this->request()",", and the user with ",[321,496,497],{},"$this->request()->user()",[477,499,500],{},"The default perimeter adds nothing: every row of the model, after its global scopes, exists.",[477,502,503,504,507],{},"Put it on your base resource, ",[321,505,506],{},"app\u002FRest\u002FResources\u002FResource.php",", when its constraints apply to every resource.",[509,510,512],"h3",{"id":511},"resources-without-a-perimeter","Resources without a perimeter",[318,514,515,518,519,521,522,525],{},[321,516,517],{},"php artisan rest:check"," lists the resources that the routes reach, through their relations too, and fails when one of them does not override ",[321,520,323],{},": every row of such a resource is visible to the users who pass ",[321,523,524],{},"viewAny",". Run it in CI. Mark a resource whose rows are meant for all these users, such as countries, with an attribute:",[326,527,529],{"className":328,"code":528,"language":330,"meta":331,"style":331},"use Lomkit\\Rest\\Attributes\\WithoutPerimeter;\n\n#[WithoutPerimeter]\nclass CountryResource extends Resource\n{\n    public static string $model = Country::class;\n}\n",[321,530,531,555,559,564,578,582,611],{"__ignoreMap":331},[335,532,533,535,538,540,543,545,548,550,553],{"class":337,"line":338},[335,534,342],{"class":341},[335,536,537],{"class":345}," Lomkit",[335,539,350],{"class":349},[335,541,542],{"class":345},"Rest",[335,544,350],{"class":349},[335,546,547],{"class":345},"Attributes",[335,549,350],{"class":349},[335,551,552],{"class":345},"WithoutPerimeter",[335,554,371],{"class":349},[335,556,557],{"class":337,"line":374},[335,558,378],{"emptyLinePlaceholder":377},[335,560,561],{"class":337,"line":381},[335,562,563],{"class":345},"#[WithoutPerimeter]\n",[335,565,566,569,572,575],{"class":337,"line":413},[335,567,568],{"class":384},"class",[335,570,571],{"class":398}," CountryResource",[335,573,574],{"class":384}," extends",[335,576,577],{"class":398}," Resource\n",[335,579,580],{"class":337,"line":419},[335,581,416],{"class":349},[335,583,584,587,590,593,595,598,601,604,607,609],{"class":337,"line":469},[335,585,586],{"class":384},"    public",[335,588,589],{"class":384}," static",[335,591,592],{"class":341}," string",[335,594,401],{"class":349},[335,596,597],{"class":345},"model ",[335,599,600],{"class":349},"=",[335,602,603],{"class":398}," Country",[335,605,606],{"class":349},"::",[335,608,568],{"class":341},[335,610,371],{"class":349},[335,612,614],{"class":337,"line":613},7,[335,615,472],{"class":349},[326,617,622],{"className":618,"code":620,"language":621,"meta":331},[619],"language-text","  rows ... 1 resource with a perimeter, 1 marked #[WithoutPerimeter]\n  App\\Rest\\Resources\\CountryResource ... #[WithoutPerimeter]\n","text",[321,623,620],{"__ignoreMap":331},[318,625,626,627,487],{},"See ",[628,629,631],"a",{"href":630},"\u002Fdigging-deeper\u002Fartisan#checking-the-application","Artisan",[633,634,635],"tip",{},[318,636,637,638,642,643,646,647,650,651,487],{},"The perimeter decides which rows ",[639,640,641],"strong",{},"exist",". A policy decides what the user may ",[639,644,645],{},"do"," with a row that exists. A row that the client may see but not change belongs in a policy, which answers ",[321,648,649],{},"403",". A row that must not exist for the client belongs in the perimeter, which answers as if the row did not exist. See ",[628,652,154],{"href":155},[313,654,656],{"id":655},"where-it-applies","Where it applies",[318,658,659],{},"The perimeter of each resource applies wherever a request reaches its rows, at every level:",[661,662,663,676],"table",{},[664,665,666],"thead",{},[667,668,669,673],"tr",{},[670,671,672],"th",{},"Request",[670,674,675],{},"The perimeter applies to",[677,678,679,690,704,724,738,746,767],"tbody",{},[667,680,681,687],{},[682,683,684],"td",{},[321,685,686],{},"search",[682,688,689],{},"the rows of the page, each include level, each relation of a dotted include, each relation of a filter path, each relation group, the subquery of a relation sort, and each level of an aggregate",[667,691,692,697],{},[682,693,694],{},[321,695,696],{},"mutate",[682,698,699,700,703],{},"the keys of every entry, at the root and under relations, each through the perimeter of its own resource, and the records of the ",[321,701,702],{},"response"," block",[667,705,706,718],{},[682,707,708,711,712,711,715],{},[321,709,710],{},"destroy",", ",[321,713,714],{},"restore",[321,716,717],{},"forceDestroy",[682,719,720,721],{},"the keys of ",[321,722,723],{},"resources",[667,725,726,729],{},[682,727,728],{},"actions",[682,730,731,732,734,735,737],{},"the rows of the ",[321,733,62],{}," target and the keys of the ",[321,736,33],{}," target",[667,739,740,743],{},[682,741,742],{},"metrics",[682,744,745],{},"the query that the metric computes on",[667,747,748,751],{},[682,749,750],{},"gates",[682,752,753,754,711,757,711,760,762,763,766],{},"the ",[321,755,756],{},"update",[321,758,759],{},"delete",[321,761,714],{}," and ",[321,764,765],{},"forceDelete"," answers of a row",[667,768,769,774],{},[682,770,771],{},[321,772,773],{},"Rest::search()",[682,775,776],{},"the same rows as the search endpoint, for the given user",[509,778,780],{"id":779},"searches","Searches",[318,782,783],{},"A search reads the rows of the page through the perimeter. Each include, each filter on a relation and each aggregate applies the perimeter of the related resource, each in its own group:",[326,785,789],{"className":786,"code":787,"language":788,"meta":331,"style":331},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\"search\": {\"filters\": [{\"field\": \"author.tags.name\", \"value\": \"featured\"}]}}\n","json",[321,790,791],{"__ignoreMap":331},[335,792,793,796,799,801,803,806,809,811,814,816,818,821,823,826,828,830,833,836,838,840,842,845,847,849,851,854,856],{"class":337,"line":338},[335,794,795],{"class":349},"{",[335,797,798],{"class":349},"\"",[335,800,686],{"class":384},[335,802,798],{"class":349},[335,804,805],{"class":349},":",[335,807,808],{"class":349}," {",[335,810,798],{"class":349},[335,812,813],{"class":398},"filters",[335,815,798],{"class":349},[335,817,805],{"class":349},[335,819,820],{"class":349}," [{",[335,822,798],{"class":349},[335,824,825],{"class":341},"field",[335,827,798],{"class":349},[335,829,805],{"class":349},[335,831,832],{"class":349}," \"",[335,834,835],{"class":441},"author.tags.name",[335,837,798],{"class":349},[335,839,447],{"class":349},[335,841,832],{"class":349},[335,843,844],{"class":341},"value",[335,846,798],{"class":349},[335,848,805],{"class":349},[335,850,832],{"class":349},[335,852,853],{"class":441},"featured",[335,855,798],{"class":349},[335,857,858],{"class":349},"}]}}\n",[318,860,861,862,865],{},"This filter matches a post only through an author and a tag that the perimeters of their resources keep. An include renders ",[321,863,864],{},"null",", or leaves a row out, when the perimeter of its resource leaves the related row out.",[509,867,869],{"id":868},"writes","Writes",[318,871,872,873,876],{},"The keys of a mutation are checked during validation, with one query per resource class, through the perimeter of the resource of each row. A key outside the perimeter gives a ",[321,874,875],{},"422",", with the message of a key that does not exist:",[326,878,880],{"className":786,"code":879,"language":788,"meta":331,"style":331},"{\n  \"message\": \"The selected mutate.0.key is invalid.\",\n  \"errors\": {\n    \"mutate.0.key\": [\"The selected mutate.0.key is invalid.\"]\n  }\n}\n",[321,881,882,886,908,922,946,951],{"__ignoreMap":331},[335,883,884],{"class":337,"line":338},[335,885,416],{"class":349},[335,887,888,891,894,896,898,900,903,905],{"class":337,"line":374},[335,889,890],{"class":349},"  \"",[335,892,893],{"class":384},"message",[335,895,798],{"class":349},[335,897,805],{"class":349},[335,899,832],{"class":349},[335,901,902],{"class":441},"The selected mutate.0.key is invalid.",[335,904,798],{"class":349},[335,906,907],{"class":349},",\n",[335,909,910,912,915,917,919],{"class":337,"line":381},[335,911,890],{"class":349},[335,913,914],{"class":384},"errors",[335,916,798],{"class":349},[335,918,805],{"class":349},[335,920,921],{"class":349}," {\n",[335,923,924,927,930,932,934,937,939,941,943],{"class":337,"line":413},[335,925,926],{"class":349},"    \"",[335,928,929],{"class":398},"mutate.0.key",[335,931,798],{"class":349},[335,933,805],{"class":349},[335,935,936],{"class":349}," [",[335,938,798],{"class":349},[335,940,902],{"class":441},[335,942,798],{"class":349},[335,944,945],{"class":349},"]\n",[335,947,948],{"class":337,"line":419},[335,949,950],{"class":349},"  }\n",[335,952,953],{"class":337,"line":469},[335,954,472],{"class":349},[474,956,957,960,969],{},[477,958,959],{},"The rows that this query loads are the rows that the mutation writes: the perimeter runs once per request, before any write.",[477,961,962,963,965,966,968],{},"A created row is not checked against the perimeter: it is written, and its record in the ",[321,964,702],{}," block is ",[321,967,864],{}," when the perimeter leaves it out.",[477,970,971,762,974,977],{},[321,972,973],{},"sync",[321,975,976],{},"toggle"," compare their keys with the attached rows that the perimeter of the related resource returns. An attached row outside it stays attached.",[509,979,981],{"id":980},"keys-out-of-reach","Keys out of reach",[318,983,984,985,988,989,991,992,995,996,998,999,1001,1002,711,1004,762,1006,1008,1009,487],{},"When a request names keys that the perimeter of their resource does not return, the package dispatches the ",[321,986,987],{},"Lomkit\\Rest\\Events\\KeysOutOfReach"," event before the ",[321,990,875],{},", once per resource and per request, so that a listener can record it. It covers the ",[321,993,994],{},"key"," of ",[321,997,696],{}," entries and of relation entries, the ",[321,1000,723],{}," of an action, ",[321,1003,710],{},[321,1005,714],{},[321,1007,717],{},". The answer does not change. See ",[628,1010,1012],{"href":1011},"\u002Fdigging-deeper\u002Fevents-and-hooks#keys-out-of-reach","Events and hooks",[509,1014,1016],{"id":1015},"deletions","Deletions",[318,1018,1019,711,1021,762,1023,1025,1026,762,1028,1030,1031,1034,1035,487],{},[321,1020,710],{},[321,1022,714],{},[321,1024,717],{}," read their keys through the perimeter, with the trashed rows on ",[321,1027,714],{},[321,1029,717],{},". A key outside it gives ",[321,1032,1033],{},"The selected resources.0 is invalid."," See ",[628,1036,1037],{"href":119},"Deleting",[313,1039,1041],{"id":1040},"one-perimeter-for-every-endpoint","One perimeter for every endpoint",[318,1043,1044],{},"A resource has one perimeter. To let one endpoint reach rows that the others leave out, branch on the endpoint of the request:",[326,1046,1048],{"className":328,"code":1047,"language":330,"meta":331,"style":331},"use Illuminate\\Contracts\\Database\\Eloquent\\Builder;\nuse Lomkit\\Rest\\Http\\Routing\\Endpoint;\n\npublic function perimeterQuery(Builder $query): Builder\n{\n    if ($this->request()->endpoint() === Endpoint::Mutate) {\n        return $query;\n    }\n\n    return $query->where('published', true);\n}\n",[321,1049,1050,1074,1101,1105,1125,1129,1162,1173,1179,1184,1211],{"__ignoreMap":331},[335,1051,1052,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072],{"class":337,"line":338},[335,1053,342],{"class":341},[335,1055,346],{"class":345},[335,1057,350],{"class":349},[335,1059,353],{"class":345},[335,1061,350],{"class":349},[335,1063,358],{"class":345},[335,1065,350],{"class":349},[335,1067,363],{"class":345},[335,1069,350],{"class":349},[335,1071,368],{"class":345},[335,1073,371],{"class":349},[335,1075,1076,1078,1080,1082,1084,1086,1089,1091,1094,1096,1099],{"class":337,"line":374},[335,1077,342],{"class":341},[335,1079,537],{"class":345},[335,1081,350],{"class":349},[335,1083,542],{"class":345},[335,1085,350],{"class":349},[335,1087,1088],{"class":345},"Http",[335,1090,350],{"class":349},[335,1092,1093],{"class":345},"Routing",[335,1095,350],{"class":349},[335,1097,1098],{"class":345},"Endpoint",[335,1100,371],{"class":349},[335,1102,1103],{"class":337,"line":381},[335,1104,378],{"emptyLinePlaceholder":377},[335,1106,1107,1109,1111,1113,1115,1117,1119,1121,1123],{"class":337,"line":413},[335,1108,385],{"class":384},[335,1110,388],{"class":384},[335,1112,392],{"class":391},[335,1114,395],{"class":349},[335,1116,368],{"class":398},[335,1118,401],{"class":349},[335,1120,404],{"class":345},[335,1122,407],{"class":349},[335,1124,410],{"class":398},[335,1126,1127],{"class":337,"line":419},[335,1128,416],{"class":349},[335,1130,1131,1134,1137,1139,1141,1144,1147,1150,1153,1155,1157,1160],{"class":337,"line":469},[335,1132,1133],{"class":422},"    if",[335,1135,1136],{"class":349}," ($this->",[335,1138,453],{"class":391},[335,1140,456],{"class":349},[335,1142,1143],{"class":391},"endpoint",[335,1145,1146],{"class":349},"()",[335,1148,1149],{"class":349}," ===",[335,1151,1152],{"class":398}," Endpoint",[335,1154,606],{"class":349},[335,1156,106],{"class":345},[335,1158,1159],{"class":349},")",[335,1161,921],{"class":349},[335,1163,1164,1167,1169,1171],{"class":337,"line":613},[335,1165,1166],{"class":422},"        return",[335,1168,401],{"class":349},[335,1170,404],{"class":345},[335,1172,371],{"class":349},[335,1174,1176],{"class":337,"line":1175},8,[335,1177,1178],{"class":349},"    }\n",[335,1180,1182],{"class":337,"line":1181},9,[335,1183,378],{"emptyLinePlaceholder":377},[335,1185,1187,1189,1191,1193,1195,1197,1199,1201,1204,1206,1208],{"class":337,"line":1186},10,[335,1188,423],{"class":422},[335,1190,401],{"class":349},[335,1192,404],{"class":345},[335,1194,430],{"class":349},[335,1196,433],{"class":391},[335,1198,395],{"class":349},[335,1200,438],{"class":349},[335,1202,1203],{"class":441},"published",[335,1205,438],{"class":349},[335,1207,447],{"class":349},[335,1209,1210],{"class":349}," true);\n",[335,1212,1214],{"class":337,"line":1213},11,[335,1215,472],{"class":349},[318,1217,1218,1219,1221],{},"A row that the perimeter leaves out on one endpoint only gives a ",[321,1220,875],{}," on that endpoint only. A search still answers that endpoint's gates from the policy: put a condition that a gate must follow in the policy.",[313,1223,1225],{"id":1224},"conditions-stay-grouped","Conditions stay grouped",[318,1227,1228,1229,1232,1233,1236],{},"The conditions of the perimeter form one group, joined to the rest of the query with ",[321,1230,1231],{},"and",". An ",[321,1234,1235],{},"orWhere()"," in it cannot widen the filters of the client or the keys of a write:",[326,1238,1240],{"className":328,"code":1239,"language":330,"meta":331,"style":331},"public function perimeterQuery(Builder $query): Builder\n{\n    return $query\n        ->where('user_id', $this->request()->user()->id)\n        ->orWhere('public', true);\n}\n",[321,1241,1242,1262,1266,1275,1309,1328],{"__ignoreMap":331},[335,1243,1244,1246,1248,1250,1252,1254,1256,1258,1260],{"class":337,"line":338},[335,1245,385],{"class":384},[335,1247,388],{"class":384},[335,1249,392],{"class":391},[335,1251,395],{"class":349},[335,1253,368],{"class":398},[335,1255,401],{"class":349},[335,1257,404],{"class":345},[335,1259,407],{"class":349},[335,1261,410],{"class":398},[335,1263,1264],{"class":337,"line":374},[335,1265,416],{"class":349},[335,1267,1268,1270,1272],{"class":337,"line":381},[335,1269,423],{"class":422},[335,1271,401],{"class":349},[335,1273,1274],{"class":345},"query\n",[335,1276,1277,1280,1282,1284,1286,1289,1291,1293,1295,1297,1299,1301,1303,1306],{"class":337,"line":413},[335,1278,1279],{"class":349},"        ->",[335,1281,433],{"class":391},[335,1283,395],{"class":349},[335,1285,438],{"class":349},[335,1287,1288],{"class":441},"user_id",[335,1290,438],{"class":349},[335,1292,447],{"class":349},[335,1294,450],{"class":349},[335,1296,453],{"class":391},[335,1298,456],{"class":349},[335,1300,459],{"class":391},[335,1302,456],{"class":349},[335,1304,1305],{"class":345},"id",[335,1307,1308],{"class":349},")\n",[335,1310,1311,1313,1316,1318,1320,1322,1324,1326],{"class":337,"line":419},[335,1312,1279],{"class":349},[335,1314,1315],{"class":391},"orWhere",[335,1317,395],{"class":349},[335,1319,438],{"class":349},[335,1321,385],{"class":441},[335,1323,438],{"class":349},[335,1325,447],{"class":349},[335,1327,1210],{"class":349},[335,1329,1330],{"class":337,"line":469},[335,1331,472],{"class":349},[318,1333,1334,1335,1338],{},"This perimeter runs as ",[321,1336,1337],{},"(user_id = ? or public = ?) and ...",", whatever the request adds after it. The conditions of scopes and instructions are grouped the same way.",[313,1340,1342],{"id":1341},"text-searches-on-a-search-engine","Text searches on a search engine",[318,1344,1345,1346,1348,1349,805],{},"A text search that runs on a Laravel Scout search engine takes its rows from the index: the rows of its page are loaded by key, without ",[321,1347,323],{},". Its resource declares the perimeter of the index with ",[321,1350,1351],{},"perimeter()",[326,1353,1355],{"className":328,"code":1354,"language":330,"meta":331,"style":331},"use Lomkit\\Rest\\Fields\\Integer;\nuse Lomkit\\Rest\\Text\\Engine\\EngineQuery;\nuse Lomkit\\Rest\\Text\\ScoutEngine;\nuse Lomkit\\Rest\\Text\\TextSearch;\n\npublic function text(): ?TextSearch\n{\n    return ScoutEngine::make()->perimeter(\n        fn (EngineQuery $query) => $query->where('team_id', '=', $this->request()->user()->team_id),\n        [Integer::make('team_id')],\n    );\n}\n",[321,1356,1357,1378,1405,1426,1447,1451,1469,1473,1493,1554,1576,1581],{"__ignoreMap":331},[335,1358,1359,1361,1363,1365,1367,1369,1371,1373,1376],{"class":337,"line":338},[335,1360,342],{"class":341},[335,1362,537],{"class":345},[335,1364,350],{"class":349},[335,1366,542],{"class":345},[335,1368,350],{"class":349},[335,1370,42],{"class":345},[335,1372,350],{"class":349},[335,1374,1375],{"class":345},"Integer",[335,1377,371],{"class":349},[335,1379,1380,1382,1384,1386,1388,1390,1393,1395,1398,1400,1403],{"class":337,"line":374},[335,1381,342],{"class":341},[335,1383,537],{"class":345},[335,1385,350],{"class":349},[335,1387,542],{"class":345},[335,1389,350],{"class":349},[335,1391,1392],{"class":345},"Text",[335,1394,350],{"class":349},[335,1396,1397],{"class":345},"Engine",[335,1399,350],{"class":349},[335,1401,1402],{"class":345},"EngineQuery",[335,1404,371],{"class":349},[335,1406,1407,1409,1411,1413,1415,1417,1419,1421,1424],{"class":337,"line":381},[335,1408,342],{"class":341},[335,1410,537],{"class":345},[335,1412,350],{"class":349},[335,1414,542],{"class":345},[335,1416,350],{"class":349},[335,1418,1392],{"class":345},[335,1420,350],{"class":349},[335,1422,1423],{"class":345},"ScoutEngine",[335,1425,371],{"class":349},[335,1427,1428,1430,1432,1434,1436,1438,1440,1442,1445],{"class":337,"line":413},[335,1429,342],{"class":341},[335,1431,537],{"class":345},[335,1433,350],{"class":349},[335,1435,542],{"class":345},[335,1437,350],{"class":349},[335,1439,1392],{"class":345},[335,1441,350],{"class":349},[335,1443,1444],{"class":345},"TextSearch",[335,1446,371],{"class":349},[335,1448,1449],{"class":337,"line":419},[335,1450,378],{"emptyLinePlaceholder":377},[335,1452,1453,1455,1457,1460,1463,1466],{"class":337,"line":469},[335,1454,385],{"class":384},[335,1456,388],{"class":384},[335,1458,1459],{"class":391}," text",[335,1461,1462],{"class":349},"():",[335,1464,1465],{"class":349}," ?",[335,1467,1468],{"class":398},"TextSearch\n",[335,1470,1471],{"class":337,"line":613},[335,1472,416],{"class":349},[335,1474,1475,1477,1480,1482,1485,1487,1490],{"class":337,"line":1175},[335,1476,423],{"class":422},[335,1478,1479],{"class":398}," ScoutEngine",[335,1481,606],{"class":349},[335,1483,1484],{"class":391},"make",[335,1486,456],{"class":349},[335,1488,1489],{"class":391},"perimeter",[335,1491,1492],{"class":349},"(\n",[335,1494,1495,1498,1501,1503,1505,1507,1509,1512,1514,1516,1518,1520,1522,1524,1526,1528,1530,1533,1535,1537,1539,1541,1543,1545,1547,1549,1551],{"class":337,"line":1181},[335,1496,1497],{"class":384},"        fn",[335,1499,1500],{"class":349}," (",[335,1502,1402],{"class":398},[335,1504,401],{"class":349},[335,1506,404],{"class":345},[335,1508,1159],{"class":349},[335,1510,1511],{"class":349}," =>",[335,1513,401],{"class":349},[335,1515,404],{"class":345},[335,1517,430],{"class":349},[335,1519,433],{"class":391},[335,1521,395],{"class":349},[335,1523,438],{"class":349},[335,1525,442],{"class":441},[335,1527,438],{"class":349},[335,1529,447],{"class":349},[335,1531,1532],{"class":349}," '",[335,1534,600],{"class":441},[335,1536,438],{"class":349},[335,1538,447],{"class":349},[335,1540,450],{"class":349},[335,1542,453],{"class":391},[335,1544,456],{"class":349},[335,1546,459],{"class":391},[335,1548,456],{"class":349},[335,1550,442],{"class":345},[335,1552,1553],{"class":349},"),\n",[335,1555,1556,1559,1561,1563,1565,1567,1569,1571,1573],{"class":337,"line":1186},[335,1557,1558],{"class":349},"        [",[335,1560,1375],{"class":398},[335,1562,606],{"class":349},[335,1564,1484],{"class":391},[335,1566,395],{"class":349},[335,1568,438],{"class":349},[335,1570,442],{"class":441},[335,1572,438],{"class":349},[335,1574,1575],{"class":349},")],\n",[335,1577,1578],{"class":337,"line":1213},[335,1579,1580],{"class":349},"    );\n",[335,1582,1584],{"class":337,"line":1583},12,[335,1585,472],{"class":349},[318,1587,1588,1589,1591,1592,487],{},"Declare there every condition of ",[321,1590,323],{}," that keeps rows from some users. Includes and aggregates of such a search still apply the perimeter of their own resource. See ",[628,1593,92],{"href":93},[313,1595,1597],{"id":1596},"global-scopes-and-tenants","Global scopes and tenants",[318,1599,1600,1601,1604],{},"The global scopes of the model apply under the perimeter. A perimeter can take in rows that a global scope leaves out, such as with ",[321,1602,1603],{},"withTrashed()",", and the write endpoints then reach them.",[318,1606,1607],{},"With several tenants, the perimeter is the place to scope every resource to the current tenant, on your base resource. A global scope of the model works too, and also applies to the rows of a search engine page.",[1609,1610,1611],"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);}",{"title":331,"searchDepth":338,"depth":374,"links":1613},[1614,1617,1623,1624,1625,1626],{"id":315,"depth":374,"text":316,"children":1615},[1616],{"id":511,"depth":381,"text":512},{"id":655,"depth":374,"text":656,"children":1618},[1619,1620,1621,1622],{"id":779,"depth":381,"text":780},{"id":868,"depth":381,"text":869},{"id":980,"depth":381,"text":981},{"id":1015,"depth":381,"text":1016},{"id":1040,"depth":374,"text":1041},{"id":1224,"depth":374,"text":1225},{"id":1341,"depth":374,"text":1342},{"id":1596,"depth":374,"text":1597},"perimeterQuery() sets the rows that exist for a client, on every endpoint and at every level of a request. Learn where it applies and how to write it.","md",null,{},{"title":54,"description":1627},{"loc":55},"7P7scPWRvB-NouPtC5FOcZU09E7mtiPxWMV2kp8oemw",[1635,1637],{"title":50,"path":51,"stem":52,"description":1636,"children":-1},"Field rules, resource rules, rules that depend on the entry, labels and messages, unknown keys, and how the package validates each payload in one pass.",{"title":58,"path":59,"stem":60,"description":1638,"children":-1},"Page sizes, include limits, capped totals, and the limits of rest.limits on lists, depths, totals, values, response rows, action jobs and metric groups.",1794181350365]