AutomatedLink::onBeforeWrite()   A
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.3554
c 0
b 0
f 0
cc 5
nc 2
nop 0
1
<?php
2
/**
3
 * Plugin: SEOToolbox
4
 * Author: Dylan Grech
5
 * Copyright: 2016
6
 *
7
 * Automated Link is a dataobject that contains all the data
8
 * about a link that should be created automatically to a page
9
 *
10
 * @method SiteTree|null Page()
11
 * @property string Phrase
12
 * @property string TitleTag
13
 * @property string AnchorTag
14
 * @property boolean NewWindow
15
 * @property boolean NoFollow
16
 * @property boolean SelfLinking
17
 * @property boolean CaseSensitive
18
 * @property int MaxLinksPerPage
19
 * @property int Priority
20
 * @property int PageID
21
 */
22
class AutomatedLink extends DataObject implements PermissionProvider {
23
24
    private static $db = array(
25
        'Phrase'     	  => 'VARCHAR(255)',
26
        'TitleTag'   	  => 'VARCHAR(255)',
27
        'AnchorTag' 	  => 'VARCHAR(255)',
28
        'NewWindow'  	  => 'Boolean',
29
        'NoFollow'   	  => 'Boolean',
30
        'SelfLinking'     => 'Boolean',
31
        'CaseSensitive'   => 'Boolean',
32
        'MaxLinksPerPage' => 'INT',
33
        'Priority'		  => 'Int'
34
    );
35
36
    private static $defaults = array(
37
        'MaxLinksPerPage' => 10
38
    );
39
40
    private static $default_sort = 'Priority';
41
42
    private static $has_one = array(
43
        'Page' => 'SiteTree'
44
    );
45
46
    private static $summary_fields    = array( 'Phrase', 'PointsTo' );
47
    private static $searchable_fields = array( 'Phrase' );
48
    private static $singular_name	  = 'Automated Link';
49
    private static $plural_name	      = 'Automated Links';
50
    private static $parsableFields    = array();
51
52
    /**
53
     * Get the url of the page linked to this object
54
     *
55
     * @return string
56
     */
57
    public function PointsTo(){
58
        return $this->Page()->Link();
59
    }
60
61
    /**
62
     * Return the phrase set for this object
63
     *
64
     * @return string
65
     */
66
    public function Title(){
67
        return $this->Phrase;
68
    }
69
70
    /**
71
     * Return the rendered version of this object
72
     *
73
     * @return String
74
     */
75
    public function forTemplate(){
76
        return $this->getHTML();
77
    }
78
79
    public function canView( $member = false ){
80
        return Permission::check('AUTOMATEDLINK_VIEW');
81
    }
82
83
    public function canEdit( $member = false ){
84
        return Permission::check('AUTOMATEDLINK_EDIT');
85
    }
86
87
    public function canDelete( $member = false ){
88
        return Permission::check('AUTOMATEDLINK_DELETE');
89
    }
90
91
    public function canCreate( $member = false ){
92
        return Permission::check('AUTOMATEDLINK_CREATE');
93
    }
94
95
    public function providePermissions() {
96
       return array(
97
         'AUTOMATEDLINK_VIEW'   => 'View Automated Links',
98
         'AUTOMATEDLINK_EDIT'   => 'Edit Automated Links',
99
         'AUTOMATEDLINK_DELETE' => 'Delete Automated Links',
100
         'AUTOMATEDLINK_CREATE' => 'Create Automated Links',
101
       );
102
     }
103
104
	public function requireDefaultRecords(){
105
		parent::requireDefaultRecords();
106
107
		// Update all links to redirector pages during dev/build
108
		foreach( self::get() as $link ) {
109
		    $link->CheckAndUpdateDestination( true );
110
		}
111
	}
112
113
	/**
114
	 * Returns the HTML Representation of this object
115
	 *
116
     * @param  String $originalPhrase
117
	 * @return String
118
	 */
119
	public function getHTML($originalPhrase = NULL) {
120
		$link     = ($this->PageID) ? $this->Page()->Link() : '#';
121
		$title    = ($this->TitleTag) ? "title='{$this->TitleTag}'" : '';
122
		$nofollow = ($this->NoFollow) ? 'rel="nofollow"' : '';
123
		$newtab   = ($this->NewWindow) ? 'target="_blank"' : '';
124
        $anchor = ($originalPhrase) ? $originalPhrase : $this->Phrase;
125
		$link     = ($this->AnchorTag) ? rtrim($link, '#').'#'.$this->AnchorTag : $link;
126
		return "<a href=\"$link\" $title $nofollow $newtab data-id=\"{$this->ID}\">{$anchor}</a>";
127
	}
128
129
	public function getCMSFields() {
130
		$fields = FieldList::create(TabSet::create('Root'));
131
132
		$fields->addFieldsToTab('Root.LinkSettings', array(
133
			TextField::create('Phrase', 'Phrase to search for', $this->Phrase, 255),
134
			TextField::create('TitleTag', 'Title Tag', $this->TitleTag, 255),
135
			TextField::create('AnchorTag', 'Anchor Tag(#)', $this->AnchorTag, 255),
136
			FieldGroup::create(
137
				CheckboxField::create('NoFollow'),
138
				CheckboxField::create('NewWindow'),
139
				CheckboxField::create('SelfLinking', 'Allow page to link to itself'),
140
				CheckboxField::create('CaseSensitive', 'Match the case of the phrase')
141
			),
142
			NumericField::create('MaxLinksPerPage', 'Maximum amount of this link to be created on a single page( 0 = unlimited )'),
143
			TreeDropdownField::create('PageID', 'Page to link to', 'SiteTree')
144
		));
145
146
		$settings = GlobalAutoLinkSettings::get_current();
147
		if ($settings) {
148
			$fields->addFieldsToTab('Root.Global', array(
149
				NumericField::create(
150
					'Global_MaxLinksPerPage',
151
					'Maximum amount of links a single page can have ( 0 = unlimited )',
152
					$settings->MaxLinksPerPage
153
				),
154
				TextField::create(
155
					'Global_ExcludeTags',
156
					'Do not include links into these HTML Tags ( comma seperated )',
157
					$settings->ExcludeTags
158
				),
159
				TextField::create(
160
				    'Global_AddTo',
161
				    'Page types where links should be created in ( leave blank for all page types )',
162
				    $settings->AddTo ),
163
				TextField::create(
164
					'Global_IncludeIn',
165
					'Include Links into these fields ( comma seperated & field must support html injection )',
166
					$settings->IncludeIn
167
				)
168
			));
169
		}
170
171
		return $fields;
172
	}
173
174
    public function getCMSValidator() {
175
        return new RequiredFields(array('Phrase', 'PageID'));
176
    }
177
178
	/**
179
	 * Save the Global Settings into the
180
	 * Global Auto Link Settings Object
181
	 *
182
	 * @return void
183
	 */
184
	public function onBeforeWrite() {
185
		parent::onBeforeWrite();
186
187
		$settings = GlobalAutoLinkSettings::get_current();
188
		if ($settings) {
189
190
			foreach ($this->getChangedFields() as $field => $value) {
191
				if (strpos($field, 'Global_') === 0 && isset($value['after'])) {
192
					$field = str_replace('Global_', '', $field);
193
					$settings->$field = $value['after'];
194
				}
195
			}
196
197
			$settings->write();
198
		}
199
200
		$this->CheckAndUpdateDestination();
201
	}
202
203
	/**
204
	 * Checks if the destination is a redirector page if so
205
	 * it updates it to the destination of the redirector page
206
	 *
207
	 * @Boolean $write - Write the changes if any
208
	 * @return void
209
	 */
210
	public function CheckAndUpdateDestination( $write = false ){
211
		$this->extend('beforeCheckAndUpdateDestination', $write);
212
213
		if( $this->PageID && $this->Page() &&
214
			$this->Page()->ClassName == 'RedirectorPage' &&
215
			$this->Page()->LinkToID && $this->Page()->RedirectionType == 'Internal' )
216
		{
217
			$this->PageID = $this->Page()->LinkToID;
218
			if( $write ) {
219
			    $this->write();
220
			}
221
		}
222
	}
223
224
    /**
225
     * Checks if the field is parable
226
     *
227
     * @param SiteTree $page
228
     * @param String   $field
229
     * @return Boolean
230
     */
231
    public static function isFieldParsable(SiteTree $page, $field) {
232
        if (!isset(self::$parsableFields[$page->ID]) || !isset(self::$parsableFields[$page->ID][$field])) {
233
            $fields = self::getAllDatabaseFields($page->ClassName);
234
            self::$parsableFields[$page->ID][$field] =
235
                (Boolean) array_key_exists($field, $fields) && strtolower($fields[$field]) === 'htmltext' && $page->$field;
236
        }
237
238
        return self::$parsableFields[$page->ID][$field];
239
    }
240
241
    /**
242
     * Checks if this link can be added to the provided
243
     * page and field
244
     *
245
     * @param ContentController $controller
246
     * @return Boolean
247
     */
248
    public function canBeAdded( ContentController $controller ){
249
        return ( $this->SelfLinking || $controller->ID != $this->PageID );
250
    }
251
252
    /**
253
     * Turn the string passed into a DOMDocument object
254
     *
255
     * @param string $html
256
     * @return DOMDocument
257
     */
258
    public static function constructDOMDocument($html){
259
        if( class_exists( 'HTML5_Parser' ) ){
260
            $html5 = HTML5_Parser::parse( $html );
261
            if($html5 instanceof DOMNodeList){
262
                $dom = new DOMDocument();
263
                while($html5->length > 0) {
264
                    $dom->appendChild($html5->item(0));
265
                }
266
            }else{
267
                $dom = $html5;
268
            }
269
        } else{
270
            $dom = new DOMDocument();
271
            $dom->loadHTML( $html );
272
        }
273
274
        return $dom;
275
    }
276
277
    /**
278
     * Returns an array with all the database fields $class has
279
     *
280
     * @param string $class
281
     * @return array
282
     */
283
    public static function getAllDatabaseFields($class){
284
        $fields = array();
285
        foreach (ClassInfo::ancestry($class, true) as $ancestor){
286
            $fields = array_merge($fields, (array) DataObject::database_fields($ancestor));
287
        }
288
        return $fields;
289
    }
290
}
291