1 | <?php |
||
2 | |||
3 | namespace LeKoala\Blocks; |
||
4 | |||
5 | use Page; |
||
6 | use SilverStripe\ORM\ArrayList; |
||
7 | use SilverStripe\Dev\TaskRunner; |
||
8 | use SilverStripe\Control\Director; |
||
9 | use SilverStripe\Forms\FormAction; |
||
10 | use SilverStripe\GraphQL\Controller; |
||
11 | use SilverStripe\SiteConfig\SiteConfig; |
||
12 | use SilverStripe\Forms\GridField\GridField; |
||
13 | use SilverStripe\Forms\GridField\GridFieldPageCount; |
||
14 | use SilverStripe\Forms\GridField\GridFieldPaginator; |
||
15 | use SilverStripe\Forms\GridField\GridFieldToolbarHeader; |
||
16 | use Symbiote\GridFieldExtensions\GridFieldOrderableRows; |
||
17 | use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; |
||
18 | |||
19 | /** |
||
20 | * A page mode of blocks |
||
21 | * |
||
22 | * Blocks html are rendered into the Content variable on save, so everything |
||
23 | * is statically compiled |
||
24 | * |
||
25 | * This means that blocks versioning will follow page versioning and everything |
||
26 | * is published at the same time |
||
27 | * |
||
28 | * @method \SilverStripe\ORM\DataList|\LeKoala\Blocks\Block[] Blocks() |
||
29 | */ |
||
30 | class BlocksPage extends Page |
||
31 | { |
||
32 | private static $table_name = 'BlocksPage'; // When using namespace, specify table name |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
33 | private static $has_many = [ |
||
0 ignored issues
–
show
|
|||
34 | "Blocks" => Block::class |
||
35 | ]; |
||
36 | private static $cascade_deletes = [ |
||
0 ignored issues
–
show
|
|||
37 | "Blocks" |
||
38 | ]; |
||
39 | /** |
||
40 | * @config |
||
41 | * @var boolean |
||
42 | */ |
||
43 | private static $wrap_blocks = true; |
||
44 | /** |
||
45 | * Track writing to prevent infinite loop |
||
46 | * |
||
47 | * @var boolean |
||
48 | */ |
||
49 | protected static $is_writing = false; |
||
50 | |||
51 | /** |
||
52 | * This helper methods helps you to generate anchorable menu for your blocks |
||
53 | * |
||
54 | * @return ArrayList |
||
55 | */ |
||
56 | public function MenuAnchorsItems() |
||
57 | { |
||
58 | $list = new ArrayList(); |
||
59 | $anchors = $this->Blocks()->exclude(['HTMLID' => null]); |
||
60 | foreach ($anchors as $block) { |
||
61 | $title = $block->MenuTitle; |
||
62 | if (!$title) { |
||
63 | $title = $block->Title; |
||
64 | } |
||
65 | $item = [ |
||
66 | 'Link' => $this->Link() . '#' . $block->HTMLID, |
||
67 | 'Title' => $title, |
||
68 | 'MenuTitle' => $title, |
||
69 | ]; |
||
70 | $list->push($item); |
||
71 | } |
||
72 | return $list; |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * @return array |
||
77 | */ |
||
78 | public function getBlocksListArray() |
||
79 | { |
||
80 | return array_unique($this->Blocks()->column('Type')); |
||
81 | } |
||
82 | |||
83 | public function getContent() |
||
84 | { |
||
85 | // If you pass ?live, content of the block will always be fully rendered and written to the database |
||
86 | if (isset($_GET['live']) && Director::isDev()) { |
||
87 | return $this->renderContent(true); |
||
88 | } |
||
89 | return $this->getField('Content'); |
||
90 | } |
||
91 | |||
92 | public function getCMSActions() |
||
93 | { |
||
94 | $fields = parent::getCMSActions(); |
||
95 | $fields->addFieldToTab('ActionMenus.MoreOptions', FormAction::create('doPublishBlocks', 'Publish all blocks')); |
||
96 | return $fields; |
||
97 | } |
||
98 | |||
99 | public function getCMSFields() |
||
100 | { |
||
101 | $fields = parent::getCMSFields(); |
||
102 | $BlocksConfig = GridFieldConfig_RecordEditor::create(); |
||
103 | $BlocksConfig->addComponent(new GridFieldOrderableRows()); |
||
104 | $BlocksConfig->removeComponentsByType(GridFieldPageCount::class); |
||
105 | $BlocksConfig->removeComponentsByType(GridFieldPaginator::class); |
||
106 | // We need to keep GridFieldToolbarHeader otherwise sorting does not work |
||
107 | $Blocks = new GridField('Blocks', '', $this->Blocks(), $BlocksConfig); |
||
108 | $fields->replaceField('Content', $Blocks); |
||
109 | return $fields; |
||
110 | } |
||
111 | |||
112 | protected function onBeforeWrite() |
||
113 | { |
||
114 | parent::onBeforeWrite(); |
||
115 | if ($this->ID) { |
||
116 | // We should refresh if a block has been updated later than the page |
||
117 | $refreshBlocks = false; |
||
118 | $maxBlockEdited = strtotime($this->Blocks()->max('LastEdited')); |
||
119 | if ($maxBlockEdited > strtotime($this->LastEdited)) { |
||
120 | $refreshBlocks = true; |
||
121 | } |
||
122 | // In site publisher, always refresh |
||
123 | // $ctrl = Controller::curr(); |
||
124 | // if($ctrl instanceof TaskRunner) { |
||
125 | // $refreshBlocks = true; |
||
126 | // } |
||
127 | $this->Content = $this->renderContent($refreshBlocks); |
||
128 | } |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * Render all blocks to get a full html document |
||
133 | * |
||
134 | * @param boolean $refreshBlocks |
||
135 | * @return string |
||
136 | */ |
||
137 | public function renderContent($refreshBlocks = false) |
||
138 | { |
||
139 | $Content = ''; |
||
140 | Block::$auto_update_page = false; |
||
141 | $wrap = self::config()->wrap_blocks; |
||
142 | foreach ($this->Blocks() as $Block) { |
||
143 | if ($wrap) { |
||
144 | $Content .= '<section'; |
||
145 | $htmlid = $Block->HTMLID; |
||
146 | if ($htmlid) { |
||
147 | $Content .= ' id="' . $htmlid . '"'; |
||
148 | } |
||
149 | $class = $Block->getClass(); |
||
150 | if ($class) { |
||
151 | $Content .= ' class="' . $class . '"'; |
||
152 | } |
||
153 | $Content .= '>'; |
||
154 | } |
||
155 | |||
156 | if ($refreshBlocks) { |
||
157 | $Block->write(); |
||
158 | } |
||
159 | $Content .= (string)$Block->forTemplate(); |
||
160 | if ($wrap) { |
||
161 | $Content .= '</section>'; |
||
162 | } |
||
163 | } |
||
164 | Block::$auto_update_page = true; |
||
165 | return $Content; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Add a block to this page |
||
170 | * Useful for programmatic scaffolding |
||
171 | * |
||
172 | * @param string $content |
||
173 | * @param string $type |
||
174 | * @return void |
||
175 | */ |
||
176 | public function addBlock($content, $type = null) |
||
177 | { |
||
178 | $block = new Block(); |
||
179 | $block->Content = $content; |
||
180 | if ($type) { |
||
181 | $block->Type = $type; |
||
182 | } |
||
183 | $block->PageID = $this->ID; |
||
184 | $block->write(); |
||
185 | } |
||
186 | } |
||
187 |