BlocksPage   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 68
c 1
b 0
f 0
dl 0
loc 155
rs 10
wmc 21

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getBlocksListArray() 0 3 1
A onBeforeWrite() 0 16 3
A getCMSFields() 0 11 1
B renderContent() 0 29 7
A MenuAnchorsItems() 0 17 3
A getCMSActions() 0 5 1
A addBlock() 0 9 2
A getContent() 0 7 3
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
The private property $table_name is not used, and could be removed.
Loading history...
33
    private static $has_many = [
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
34
        "Blocks" => Block::class
35
    ];
36
    private static $cascade_deletes = [
0 ignored issues
show
introduced by
The private property $cascade_deletes is not used, and could be removed.
Loading history...
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