[{"data":1,"prerenderedAt":1467},["ShallowReactive",2],{"navigation":3,"\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable":342,"\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable-surround":1462},[4,14,36,69,140,325],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started\u002F1.index",[9,10],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":15,"path":16,"stem":17,"children":18,"page":35},"Guides","\u002Fguides","2.guides",[19,23,27,31],{"title":20,"path":21,"stem":22},"Your First Layout","\u002Fguides\u002Fyour-first-layout","2.guides\u002F1.your-first-layout",{"title":24,"path":25,"stem":26},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","2.guides\u002F2.your-first-page-template",{"title":28,"path":29,"stem":30},"Your First Component","\u002Fguides\u002Fyour-first-component","2.guides\u002F3.your-first-component",{"title":32,"path":33,"stem":34},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","2.guides\u002F4.alternative-ui-variants",false,{"title":37,"path":38,"stem":39,"children":40,"page":35},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[41,45,49,53,57,61,65],{"title":42,"path":43,"stem":44},"How It All Works","\u002Fcore-concepts\u002Farchitecture","3.core-concepts\u002F1.architecture",{"title":46,"path":47,"stem":48},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","3.core-concepts\u002F2.the-data-model",{"title":50,"path":51,"stem":52},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","3.core-concepts\u002F3.layouts-and-pages",{"title":54,"path":55,"stem":56},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","3.core-concepts\u002F4.dynamic-pages",{"title":58,"path":59,"stem":60},"Components","\u002Fcore-concepts\u002Fcomponents","3.core-concepts\u002F5.components",{"title":62,"path":63,"stem":64},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","3.core-concepts\u002F6.draft-and-publish",{"title":66,"path":67,"stem":68},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","3.core-concepts\u002F7.admin-panel",{"title":70,"path":71,"stem":72,"children":73,"page":35},"Api","\u002Fapi","4.api",[74,78,116,120,124,128,132,136],{"title":75,"path":76,"stem":77},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F1.bundle-setup",{"title":58,"path":79,"stem":80,"children":81,"page":35},"\u002Fapi\u002Fcomponents","4.api\u002F2.components",[82,86,103],{"title":83,"path":84,"stem":85},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F2.components\u002F1.creating-components",{"title":87,"path":88,"stem":89,"children":90,"page":35},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F2.components\u002F2.annotations",[91,95,99],{"title":92,"path":93,"stem":94},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F2.components\u002F2.annotations\u002F1.publishable",{"title":96,"path":97,"stem":98},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F2.components\u002F2.annotations\u002F2.uploadable",{"title":100,"path":101,"stem":102},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F2.components\u002F2.annotations\u002F3.timestamped",{"title":104,"path":105,"stem":106,"children":107,"page":35},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F2.components\u002F3.built-ins",[108,112],{"title":109,"path":110,"stem":111},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F2.components\u002F3.built-ins\u002F1.collection-component",{"title":113,"path":114,"stem":115},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F2.components\u002F3.built-ins\u002F2.form-component",{"title":117,"path":118,"stem":119},"Dynamic & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F3.dynamic-pages",{"title":121,"path":122,"stem":123},"Users & Security","\u002Fapi\u002Fusers-and-security","4.api\u002F4.users-and-security",{"title":125,"path":126,"stem":127},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F5.data-fixtures",{"title":129,"path":130,"stem":131},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F6.configuration",{"title":133,"path":134,"stem":135},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F7.console-commands",{"title":137,"path":138,"stem":139},"Debugging & Profiler","\u002Fapi\u002Fdebugging","4.api\u002F8.debugging",{"title":141,"path":142,"stem":143,"children":144,"page":35},"Nuxt Module","\u002Fnuxt-module","5.nuxt-module",[145,149,162,178,203,207,279,304,308],{"title":146,"path":147,"stem":148},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F1.module-setup",{"title":150,"path":151,"stem":152,"children":153,"page":35},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F2.configuration",[154,158],{"title":155,"path":156,"stem":157},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F2.configuration\u002F1.nuxt-config",{"title":159,"path":160,"stem":161},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F2.configuration\u002F2.site-config-and-seo",{"title":163,"path":164,"stem":165,"children":166,"page":35},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F3.building-your-ui",[167,171,175],{"title":168,"path":169,"stem":170},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F3.building-your-ui\u002F1.creating-layouts",{"title":172,"path":173,"stem":174},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F3.building-your-ui\u002F2.creating-page-templates",{"title":83,"path":176,"stem":177},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F3.building-your-ui\u002F3.creating-components",{"title":179,"path":180,"stem":181,"children":182,"page":35},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F4.cwa-components",[183,187,191,195,199],{"title":184,"path":185,"stem":186},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F4.cwa-components\u002F1.cwa-component-group",{"title":188,"path":189,"stem":190},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F4.cwa-components\u002F2.cwa-page",{"title":192,"path":193,"stem":194},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F4.cwa-components\u002F3.cwa-link",{"title":196,"path":197,"stem":198},"\u003CCwaImage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-image","5.nuxt-module\u002F4.cwa-components\u002F4.cwa-image",{"title":200,"path":201,"stem":202},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F4.cwa-components\u002F5.cwa-default-layout",{"title":204,"path":205,"stem":206},"The useCwa() API","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F5.cwa-api",{"title":208,"path":209,"stem":210,"children":211,"page":35},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F6.composables",[212,245,262],{"title":213,"path":214,"stem":215,"children":216,"page":35},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F6.composables\u002F1.component",[217,221,225,229,233,237,241],{"title":218,"path":219,"stem":220},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F1.use-cwa-resource",{"title":222,"path":223,"stem":224},"Collection Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F2.use-cwa-collection-resource",{"title":226,"path":227,"stem":228},"Image Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-image-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F3.use-cwa-image-resource",{"title":230,"path":231,"stem":232},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form","5.nuxt-module\u002F6.composables\u002F1.component\u002F4.use-cwa-form",{"title":234,"path":235,"stem":236},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-input","5.nuxt-module\u002F6.composables\u002F1.component\u002F5.use-cwa-form-input",{"title":238,"path":239,"stem":240},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F6.composables\u002F1.component\u002F6.use-cwa-form-repeated",{"title":242,"path":243,"stem":244},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-collection","5.nuxt-module\u002F6.composables\u002F1.component\u002F7.use-cwa-form-collection",{"title":246,"path":247,"stem":248,"children":249,"page":35},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F6.composables\u002F2.admin-manager",[250,254,258],{"title":251,"path":252,"stem":253},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":255,"path":256,"stem":257},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F2.use-cwa-resource-model",{"title":259,"path":260,"stem":261},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F3.use-cwa-resource-upload",{"title":263,"path":264,"stem":265,"children":266,"page":35},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F6.composables\u002F3.utilities",[267,271,275],{"title":268,"path":269,"stem":270},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F1.use-cwa-resource-endpoint",{"title":272,"path":273,"stem":274},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F2.use-query-bound-model",{"title":276,"path":277,"stem":278},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F3.use-cwa-resource-route",{"title":280,"path":281,"stem":282,"children":283,"page":35},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F7.component-helpers",[284,288,292,296,300],{"title":285,"path":286,"stem":287},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F7.component-helpers\u002F1.images-and-uploads",{"title":289,"path":290,"stem":291},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F7.component-helpers\u002F2.collections-and-pagination",{"title":293,"path":294,"stem":295},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F7.component-helpers\u002F3.html-content",{"title":297,"path":298,"stem":299},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F7.component-helpers\u002F4.real-time-updates",{"title":301,"path":302,"stem":303},"Forms","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F7.component-helpers\u002F5.forms",{"title":305,"path":306,"stem":307},"Authentication","\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F8.authentication",{"title":309,"path":310,"stem":311,"children":312,"page":35},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[313,317,321],{"title":314,"path":315,"stem":316},"Overview","\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":318,"path":319,"stem":320},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":322,"path":323,"stem":324},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":326,"path":327,"stem":328,"children":329,"page":35},"Deployment","\u002Fdeployment","6.deployment",[330,334,338],{"title":331,"path":332,"stem":333},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":335,"path":336,"stem":337},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":339,"path":340,"stem":341},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"id":343,"title":92,"badge":344,"body":347,"description":1456,"extension":1457,"links":1458,"meta":1459,"navigation":467,"path":93,"seo":1460,"stem":94,"__hash__":1461},"docs\u002F4.api\u002F2.components\u002F2.annotations\u002F1.publishable.md",{"label":345,"color":346},"Draft","amber",{"type":348,"value":349,"toc":1444},"minimark",[350,358,363,641,644,648,718,721,725,732,773,780,784,794,852,859,868,872,875,967,977,980,1015,1019,1024,1061,1064,1068,1082,1154,1160,1164,1169,1182,1189,1193,1200,1339,1411,1426,1430,1440],[351,352,353,357],"p",{},[354,355,356],"code",{},"#[Silverback\\Publishable]"," gives your component a twin-resource draft\u002Fpublish lifecycle. An admin edits the draft privately; visitors always see the published version. Publishing is atomic — the switch happens at the database level with no stale cache window.",[359,360,362],"h2",{"id":361},"setup","Setup",[364,365,370],"pre",{"className":366,"code":367,"language":368,"meta":369,"style":369},"language-php shiki shiki-themes github-light github-dark material-theme-palenight","use Silverback\\ApiComponentsBundle\\Annotation as Silverback;\nuse Silverback\\ApiComponentsBundle\\Entity\\Core\\AbstractComponent;\nuse Silverback\\ApiComponentsBundle\\Entity\\Utility\\PublishableTrait;\n\n#[Silverback\\Publishable]\n#[ORM\\Entity]\n#[ApiResource(mercure: true)]\nclass Title extends AbstractComponent\n{\n    use PublishableTrait;\n\n    #[ORM\\Column(type: 'text', nullable: true)]\n    public ?string $title = null;\n}\n","php","",[354,371,372,407,435,462,469,486,500,525,541,547,558,563,608,635],{"__ignoreMap":369},[373,374,377,381,385,389,392,394,397,400,403],"span",{"class":375,"line":376},"line",1,[373,378,380],{"class":379},"stmX-","use",[373,382,384],{"class":383},"sc2zw"," Silverback",[373,386,388],{"class":387},"sBtbT","\\",[373,390,391],{"class":383},"ApiComponentsBundle",[373,393,388],{"class":387},[373,395,396],{"class":383},"Annotation",[373,398,399],{"class":379}," as",[373,401,384],{"class":402},"sRCss",[373,404,406],{"class":405},"sOvfz",";\n",[373,408,410,412,414,416,418,420,423,425,428,430,433],{"class":375,"line":409},2,[373,411,380],{"class":379},[373,413,384],{"class":383},[373,415,388],{"class":387},[373,417,391],{"class":383},[373,419,388],{"class":387},[373,421,422],{"class":383},"Entity",[373,424,388],{"class":387},[373,426,427],{"class":383},"Core",[373,429,388],{"class":387},[373,431,432],{"class":383},"AbstractComponent",[373,434,406],{"class":405},[373,436,438,440,442,444,446,448,450,452,455,457,460],{"class":375,"line":437},3,[373,439,380],{"class":379},[373,441,384],{"class":383},[373,443,388],{"class":387},[373,445,391],{"class":383},[373,447,388],{"class":387},[373,449,422],{"class":383},[373,451,388],{"class":387},[373,453,454],{"class":383},"Utility",[373,456,388],{"class":387},[373,458,459],{"class":383},"PublishableTrait",[373,461,406],{"class":405},[373,463,465],{"class":375,"line":464},4,[373,466,468],{"emptyLinePlaceholder":467},true,"\n",[373,470,472,476,479,481,483],{"class":375,"line":471},5,[373,473,475],{"class":474},"sPB8G","#[",[373,477,478],{"class":383},"Silverback",[373,480,388],{"class":387},[373,482,92],{"class":383},[373,484,485],{"class":474},"]\n",[373,487,489,491,494,496,498],{"class":375,"line":488},6,[373,490,475],{"class":474},[373,492,493],{"class":383},"ORM",[373,495,388],{"class":387},[373,497,422],{"class":383},[373,499,485],{"class":474},[373,501,503,505,508,511,514,517,520,523],{"class":375,"line":502},7,[373,504,475],{"class":474},[373,506,507],{"class":383},"ApiResource",[373,509,510],{"class":405},"(",[373,512,513],{"class":402},"mercure",[373,515,516],{"class":405},":",[373,518,519],{"class":387}," true",[373,521,522],{"class":405},")",[373,524,485],{"class":474},[373,526,528,532,535,538],{"class":375,"line":527},8,[373,529,531],{"class":530},"swB56","class",[373,533,534],{"class":402}," Title",[373,536,537],{"class":530}," extends",[373,539,540],{"class":402}," AbstractComponent\n",[373,542,544],{"class":375,"line":543},9,[373,545,546],{"class":405},"{\n",[373,548,550,553,556],{"class":375,"line":549},10,[373,551,552],{"class":379},"    use",[373,554,555],{"class":383}," PublishableTrait",[373,557,406],{"class":405},[373,559,561],{"class":375,"line":560},11,[373,562,468],{"emptyLinePlaceholder":467},[373,564,566,569,571,573,576,578,581,583,587,591,594,597,600,602,604,606],{"class":375,"line":565},12,[373,567,568],{"class":474},"    #[",[373,570,493],{"class":383},[373,572,388],{"class":387},[373,574,575],{"class":383},"Column",[373,577,510],{"class":405},[373,579,580],{"class":402},"type",[373,582,516],{"class":405},[373,584,586],{"class":585},"seSrl"," '",[373,588,590],{"class":589},"sLL54","text",[373,592,593],{"class":585},"'",[373,595,596],{"class":405},",",[373,598,599],{"class":402}," nullable",[373,601,516],{"class":405},[373,603,519],{"class":387},[373,605,522],{"class":405},[373,607,485],{"class":474},[373,609,611,614,618,621,624,627,630,633],{"class":375,"line":610},13,[373,612,613],{"class":530},"    public",[373,615,617],{"class":616},"sVlFx"," ?",[373,619,620],{"class":379},"string",[373,622,623],{"class":405}," $",[373,625,626],{"class":474},"title ",[373,628,629],{"class":616},"=",[373,631,632],{"class":387}," null",[373,634,406],{"class":405},[373,636,638],{"class":375,"line":637},14,[373,639,640],{"class":405},"}\n",[351,642,643],{},"That's all that's required. The trait and annotation together wire up the full lifecycle.",[359,645,647],{"id":646},"what-publishabletrait-adds","What PublishableTrait Adds",[649,650,651,667],"table",{},[652,653,654],"thead",{},[655,656,657,661,664],"tr",{},[658,659,660],"th",{},"Property",[658,662,663],{},"Type",[658,665,666],{},"Description",[668,669,670,689,704],"tbody",{},[655,671,672,678,683],{},[673,674,675],"td",{},[354,676,677],{},"publishedAt",[673,679,680],{},[354,681,682],{},"?DateTimeInterface",[673,684,685,688],{},[354,686,687],{},"null"," = unpublished draft",[655,690,691,696,701],{},[673,692,693],{},[354,694,695],{},"publishedResource",[673,697,698],{},[354,699,700],{},"?self",[673,702,703],{},"Points from draft → published twin",[655,705,706,711,715],{},[673,707,708],{},[354,709,710],{},"draftResource",[673,712,713],{},[354,714,700],{},[673,716,717],{},"Points from published → draft twin",[351,719,720],{},"The bundle creates and maintains these twins automatically. You never create the published twin manually.",[359,722,724],{"id":723},"how-it-works-at-the-api-level","How It Works at the API Level",[351,726,727,728,731],{},"The bundle intercepts requests and routes based on the caller's role and the ",[354,729,730],{},"published"," query parameter:",[649,733,734,744],{},[652,735,736],{},[655,737,738,741],{},[658,739,740],{},"Caller",[658,742,743],{},"Gets",[668,745,746,754,762],{},[655,747,748,751],{},[673,749,750],{},"Anonymous visitor",[673,752,753],{},"Published version (or 404 if never published)",[655,755,756,759],{},[673,757,758],{},"Admin in edit mode",[673,760,761],{},"Draft version",[655,763,764,770],{},[673,765,766,767],{},"Direct ",[354,768,769],{},"?published=true",[673,771,772],{},"Published version explicitly",[351,774,775,776,779],{},"The Nuxt module handles the ",[354,777,778],{},"?published=false"," parameter automatically in edit mode — you don't add it manually.",[359,781,783],{"id":782},"publishing-a-resource","Publishing a Resource",[351,785,786,787,790,791,793],{},"Send a ",[354,788,789],{},"PATCH"," with ",[354,792,677],{}," set to a date string:",[364,795,799],{"className":796,"code":797,"language":798,"meta":369,"style":369},"language-json shiki shiki-themes github-light github-dark material-theme-palenight","PATCH \u002Fcomponent\u002Ftitles\u002F018e-...\nContent-Type: application\u002Fmerge-patch+json\n\n{\n    \"publishedAt\": \"2024-01-15T10:30:00+00:00\"\n}\n","json",[354,800,801,813,818,822,826,848],{"__ignoreMap":369},[373,802,803,806,810],{"class":375,"line":376},[373,804,805],{"class":474},"PATCH \u002Fcomponent\u002Ftitles\u002F",[373,807,809],{"class":808},"scSvc","018",[373,811,812],{"class":474},"e-...\n",[373,814,815],{"class":375,"line":409},[373,816,817],{"class":474},"Content-Type: application\u002Fmerge-patch+json\n",[373,819,820],{"class":375,"line":437},[373,821,468],{"emptyLinePlaceholder":467},[373,823,824],{"class":375,"line":464},[373,825,546],{"class":405},[373,827,828,831,834,837,839,842,845],{"class":375,"line":471},[373,829,830],{"class":387},"    \"",[373,832,677],{"class":833},"sphPO",[373,835,836],{"class":387},"\"",[373,838,516],{"class":405},[373,840,841],{"class":585}," \"",[373,843,844],{"class":589},"2024-01-15T10:30:00+00:00",[373,846,847],{"class":585},"\"\n",[373,849,850],{"class":375,"line":488},[373,851,640],{"class":405},[351,853,854,855,858],{},"The bundle creates or updates the published twin and broadcasts a Mercure update if ",[354,856,857],{},"mercure: true"," is on the entity.",[351,860,861,862,790,864,867],{},"To unpublish: ",[354,863,789],{},[354,865,866],{},"\"publishedAt\": null",".",[359,869,871],{"id":870},"publish-only-validation","Publish-Only Validation",[351,873,874],{},"Some fields should only be required when going live, not while saving a draft:",[364,876,878],{"className":366,"code":877,"language":368,"meta":369,"style":369},"#[ORM\\Column(type: 'text', nullable: true)]\n#[Assert\\NotBlank(groups: ['Title:published'])]\npublic ?string $title = null;\n",[354,879,880,914,948],{"__ignoreMap":369},[373,881,882,884,886,888,890,892,894,896,898,900,902,904,906,908,910,912],{"class":375,"line":376},[373,883,475],{"class":474},[373,885,493],{"class":383},[373,887,388],{"class":387},[373,889,575],{"class":383},[373,891,510],{"class":405},[373,893,580],{"class":402},[373,895,516],{"class":405},[373,897,586],{"class":585},[373,899,590],{"class":589},[373,901,593],{"class":585},[373,903,596],{"class":405},[373,905,599],{"class":402},[373,907,516],{"class":405},[373,909,519],{"class":387},[373,911,522],{"class":405},[373,913,485],{"class":474},[373,915,916,918,921,923,926,928,931,933,936,938,941,943,946],{"class":375,"line":409},[373,917,475],{"class":474},[373,919,920],{"class":383},"Assert",[373,922,388],{"class":387},[373,924,925],{"class":383},"NotBlank",[373,927,510],{"class":405},[373,929,930],{"class":402},"groups",[373,932,516],{"class":405},[373,934,935],{"class":405}," [",[373,937,593],{"class":585},[373,939,940],{"class":589},"Title:published",[373,942,593],{"class":585},[373,944,945],{"class":405},"])",[373,947,485],{"class":474},[373,949,950,953,955,957,959,961,963,965],{"class":375,"line":437},[373,951,952],{"class":530},"public",[373,954,617],{"class":616},[373,956,620],{"class":379},[373,958,623],{"class":405},[373,960,626],{"class":474},[373,962,629],{"class":616},[373,964,632],{"class":387},[373,966,406],{"class":405},[351,968,969,970,973,974,976],{},"The convention for the publish validation group is ",[354,971,972],{},"ClassName:published",". The bundle applies this group automatically when ",[354,975,677],{}," is being set.",[351,978,979],{},"Customise the group name:",[364,981,983],{"className":366,"code":982,"language":368,"meta":369,"style":369},"#[Silverback\\Publishable(validationGroups: ['my_custom_group'])]\n",[354,984,985],{"__ignoreMap":369},[373,986,987,989,991,993,995,997,1000,1002,1004,1006,1009,1011,1013],{"class":375,"line":376},[373,988,475],{"class":474},[373,990,478],{"class":383},[373,992,388],{"class":387},[373,994,92],{"class":383},[373,996,510],{"class":405},[373,998,999],{"class":402},"validationGroups",[373,1001,516],{"class":405},[373,1003,935],{"class":405},[373,1005,593],{"class":585},[373,1007,1008],{"class":589},"my_custom_group",[373,1010,593],{"class":585},[373,1012,945],{"class":405},[373,1014,485],{"class":474},[359,1016,1018],{"id":1017},"configuring-who-can-publish","Configuring Who Can Publish",[351,1020,1021,1022,516],{},"Set the security expression in the bundle config. Only users matching this expression can set ",[354,1023,677],{},[364,1025,1029],{"className":1026,"code":1027,"language":1028,"meta":369,"style":369},"language-yaml shiki shiki-themes github-light github-dark material-theme-palenight","silverback_api_components:\n    publishable:\n        permission: \"is_granted('ROLE_ADMIN')\"\n","yaml",[354,1030,1031,1040,1047],{"__ignoreMap":369},[373,1032,1033,1037],{"class":375,"line":376},[373,1034,1036],{"class":1035},"s-h7I","silverback_api_components",[373,1038,1039],{"class":405},":\n",[373,1041,1042,1045],{"class":375,"line":409},[373,1043,1044],{"class":1035},"    publishable",[373,1046,1039],{"class":405},[373,1048,1049,1052,1054,1056,1059],{"class":375,"line":437},[373,1050,1051],{"class":1035},"        permission",[373,1053,516],{"class":405},[373,1055,841],{"class":585},[373,1057,1058],{"class":589},"is_granted('ROLE_ADMIN')",[373,1060,847],{"class":585},[351,1062,1063],{},"Non-admin users can still PATCH a resource's other fields — they just can't flip the publish switch.",[359,1065,1067],{"id":1066},"custom-property-names","Custom Property Names",[351,1069,1070,1071,1073,1074,1073,1076,1078,1079,1081],{},"The default property names (",[354,1072,677],{},", ",[354,1075,695],{},[354,1077,710],{},") match what ",[354,1080,459],{}," declares. Override them when names conflict with your own fields:",[364,1083,1085],{"className":366,"code":1084,"language":368,"meta":369,"style":369},"#[Silverback\\Publishable(\n    fieldName: 'publicationDate',\n    associationName: 'original',\n    reverseAssociationName: 'draft'\n)]\n",[354,1086,1087,1100,1117,1133,1148],{"__ignoreMap":369},[373,1088,1089,1091,1093,1095,1097],{"class":375,"line":376},[373,1090,475],{"class":474},[373,1092,478],{"class":383},[373,1094,388],{"class":387},[373,1096,92],{"class":383},[373,1098,1099],{"class":405},"(\n",[373,1101,1102,1105,1107,1109,1112,1114],{"class":375,"line":409},[373,1103,1104],{"class":402},"    fieldName",[373,1106,516],{"class":405},[373,1108,586],{"class":585},[373,1110,1111],{"class":589},"publicationDate",[373,1113,593],{"class":585},[373,1115,1116],{"class":405},",\n",[373,1118,1119,1122,1124,1126,1129,1131],{"class":375,"line":437},[373,1120,1121],{"class":402},"    associationName",[373,1123,516],{"class":405},[373,1125,586],{"class":585},[373,1127,1128],{"class":589},"original",[373,1130,593],{"class":585},[373,1132,1116],{"class":405},[373,1134,1135,1138,1140,1142,1145],{"class":375,"line":464},[373,1136,1137],{"class":402},"    reverseAssociationName",[373,1139,516],{"class":405},[373,1141,586],{"class":585},[373,1143,1144],{"class":589},"draft",[373,1146,1147],{"class":585},"'\n",[373,1149,1150,1152],{"class":375,"line":471},[373,1151,522],{"class":405},[373,1153,485],{"class":474},[351,1155,1156,1157,1159],{},"If you customise names, don't use ",[354,1158,459],{}," — declare the properties yourself using the matching names.",[359,1161,1163],{"id":1162},"migration-notes","Migration Notes",[351,1165,1166,1168],{},[354,1167,459],{}," adds:",[1170,1171,1172,1179],"ul",{},[1173,1174,1175,1176,522],"li",{},"1 nullable datetime column (",[354,1177,1178],{},"published_at",[1173,1180,1181],{},"2 nullable self-referencing foreign keys (published_resource_id, draft_resource_id)",[351,1183,1184,1185,1188],{},"Always review the generated Doctrine migration. The self-referencing keys use ",[354,1186,1187],{},"ON DELETE SET NULL"," so deleting a draft doesn't cascade to the published version.",[359,1190,1192],{"id":1191},"api-response-metadata","API Response Metadata",[351,1194,1195,1196,1199],{},"Every publishable component response includes a ",[354,1197,1198],{},"_metadata.publishable"," object visible to admin users:",[364,1201,1203],{"className":796,"code":1202,"language":798,"meta":369,"style":369},"{\n  \"@id\": \"\u002Fcomponent\u002Ftitles\u002F018e-...\",\n  \"title\": \"My Heading\",\n  \"_metadata\": {\n    \"publishable\": {\n      \"published\": true,\n      \"publishedAt\": \"2024-01-15T10:30:00+00:00\",\n      \"locationCount\": 3\n    }\n  }\n}\n",[354,1204,1205,1209,1230,1250,1264,1278,1293,1311,1325,1330,1335],{"__ignoreMap":369},[373,1206,1207],{"class":375,"line":376},[373,1208,546],{"class":405},[373,1210,1211,1214,1217,1219,1221,1223,1226,1228],{"class":375,"line":409},[373,1212,1213],{"class":387},"  \"",[373,1215,1216],{"class":833},"@id",[373,1218,836],{"class":387},[373,1220,516],{"class":405},[373,1222,841],{"class":585},[373,1224,1225],{"class":589},"\u002Fcomponent\u002Ftitles\u002F018e-...",[373,1227,836],{"class":585},[373,1229,1116],{"class":405},[373,1231,1232,1234,1237,1239,1241,1243,1246,1248],{"class":375,"line":437},[373,1233,1213],{"class":387},[373,1235,1236],{"class":833},"title",[373,1238,836],{"class":387},[373,1240,516],{"class":405},[373,1242,841],{"class":585},[373,1244,1245],{"class":589},"My Heading",[373,1247,836],{"class":585},[373,1249,1116],{"class":405},[373,1251,1252,1254,1257,1259,1261],{"class":375,"line":464},[373,1253,1213],{"class":387},[373,1255,1256],{"class":833},"_metadata",[373,1258,836],{"class":387},[373,1260,516],{"class":405},[373,1262,1263],{"class":405}," {\n",[373,1265,1266,1268,1272,1274,1276],{"class":375,"line":471},[373,1267,830],{"class":387},[373,1269,1271],{"class":1270},"sbW4m","publishable",[373,1273,836],{"class":387},[373,1275,516],{"class":405},[373,1277,1263],{"class":405},[373,1279,1280,1283,1285,1287,1289,1291],{"class":375,"line":488},[373,1281,1282],{"class":387},"      \"",[373,1284,730],{"class":808},[373,1286,836],{"class":387},[373,1288,516],{"class":405},[373,1290,519],{"class":387},[373,1292,1116],{"class":405},[373,1294,1295,1297,1299,1301,1303,1305,1307,1309],{"class":375,"line":502},[373,1296,1282],{"class":387},[373,1298,677],{"class":808},[373,1300,836],{"class":387},[373,1302,516],{"class":405},[373,1304,841],{"class":585},[373,1306,844],{"class":589},[373,1308,836],{"class":585},[373,1310,1116],{"class":405},[373,1312,1313,1315,1318,1320,1322],{"class":375,"line":527},[373,1314,1282],{"class":387},[373,1316,1317],{"class":808},"locationCount",[373,1319,836],{"class":387},[373,1321,516],{"class":405},[373,1323,1324],{"class":808}," 3\n",[373,1326,1327],{"class":375,"line":543},[373,1328,1329],{"class":405},"    }\n",[373,1331,1332],{"class":375,"line":549},[373,1333,1334],{"class":405},"  }\n",[373,1336,1337],{"class":375,"line":560},[373,1338,640],{"class":405},[649,1340,1341,1352],{},[652,1342,1343],{},[655,1344,1345,1348,1350],{},[658,1346,1347],{},"Field",[658,1349,663],{},[658,1351,666],{},[668,1353,1354,1368,1385],{},[655,1355,1356,1360,1365],{},[673,1357,1358],{},[354,1359,730],{},[673,1361,1362],{},[354,1363,1364],{},"boolean",[673,1366,1367],{},"Whether the published twin exists",[655,1369,1370,1374,1379],{},[673,1371,1372],{},[354,1373,677],{},[673,1375,1376],{},[354,1377,1378],{},"string | null",[673,1380,1381,1382,1384],{},"ISO 8601 timestamp of last publish, or ",[354,1383,687],{}," if unpublished",[655,1386,1387,1391,1396],{},[673,1388,1389],{},[354,1390,1317],{},[673,1392,1393],{},[354,1394,1395],{},"integer | null",[673,1397,1398,1399,1402,1403,1406,1407,1410],{},"Total number of places this component appears — counts both direct ",[354,1400,1401],{},"ComponentPosition"," references and ",[354,1404,1405],{},"AbstractPageData"," instances that hold it as a typed property (resolved via ",[354,1408,1409],{},"pageDataProperty"," positions at render time). Useful for showing admins \"used in N places\" before deleting.",[351,1412,1413,1415,1416,1418,1419,1422,1423,1425],{},[354,1414,1317],{}," is ",[354,1417,687],{}," for component types that have no ",[354,1420,1421],{},"getComponentPositions()"," method. Anonymous visitors do not receive ",[354,1424,1256],{}," at all.",[359,1427,1429],{"id":1428},"interaction-with-mercure","Interaction with Mercure",[351,1431,1432,1433,1435,1436,1439],{},"When a resource is published (or unpublished), if ",[354,1434,857],{}," is on the ",[354,1437,1438],{},"#[ApiResource]",", the API broadcasts an update to the hub. Every browser that has loaded the resource receives the new content in real time with no page reload needed.",[1441,1442,1443],"style",{},"html pre.shiki code .stmX-, html code.shiki .stmX-{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F78C6C}html pre.shiki code .sc2zw, html code.shiki .sc2zw{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#BABED8}html pre.shiki code .sBtbT, html code.shiki .sBtbT{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#89DDFF}html pre.shiki code .sRCss, html code.shiki .sRCss{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#FFCB6B}html pre.shiki code .sOvfz, html code.shiki .sOvfz{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#89DDFF}html pre.shiki code .sPB8G, html code.shiki .sPB8G{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#BABED8}html pre.shiki code .swB56, html code.shiki .swB56{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#C792EA}html pre.shiki code .seSrl, html code.shiki .seSrl{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#89DDFF}html pre.shiki code .sLL54, html code.shiki .sLL54{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#C3E88D}html pre.shiki code .sVlFx, html code.shiki .sVlFx{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#89DDFF}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 .scSvc, html code.shiki .scSvc{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#F78C6C}html pre.shiki code .sphPO, html code.shiki .sphPO{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#C792EA}html pre.shiki code .s-h7I, html code.shiki .s-h7I{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#F07178}html pre.shiki code .sbW4m, html code.shiki .sbW4m{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#FFCB6B}",{"title":369,"searchDepth":409,"depth":409,"links":1445},[1446,1447,1448,1449,1450,1451,1452,1453,1454,1455],{"id":361,"depth":409,"text":362},{"id":646,"depth":409,"text":647},{"id":723,"depth":409,"text":724},{"id":782,"depth":409,"text":783},{"id":870,"depth":409,"text":871},{"id":1017,"depth":409,"text":1018},{"id":1066,"depth":409,"text":1067},{"id":1162,"depth":409,"text":1163},{"id":1191,"depth":409,"text":1192},{"id":1428,"depth":409,"text":1429},"Add a draft\u002Fpublish workflow to any component so admins can edit content privately before making it live.","md",null,{},{"title":92,"description":1456},"TVNclyfQTDupRJVJQ4cIh4i-NdJKrXFzEaJZ24MUuWw",[1463,1465],{"title":83,"path":84,"stem":85,"description":1464,"children":-1},"How to define a custom content resource by extending AbstractComponent, adding API Platform metadata, and running migrations.",{"title":96,"path":97,"stem":98,"description":1466,"children":-1},"Add file upload support to any component with Flysystem adapters and optional Imagine image processing.",1782241282570]