Completed
Pull Request — master (#30)
by
unknown
10:02 queued 08:04
created

SiteTreeFullBuildEngine::runFrom()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 34
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 34
rs 6.7272
cc 7
eloc 21
nc 8
nop 1
1
<?php
2
3
/**
4
 * Similar to {@link RebuildStaticPagesTask}, but only queues pages for republication
5
 * in the {@link StaticPagesQueue}. This queue is worked off by an independent task running constantly on the server.
6
 */
7
class SiteTreeFullBuildEngine extends BuildTask {
8
9
	/**
10
	 * @var URLArrayObject
11
	 */
12
	protected $urlArrayObject;
13
14
	private static $dependencies = array(
15
		'urlArrayObject' =>  '%$URLArrayObject'
16
	);
17
18
	/**
19
	 *
20
	 * @var string
21
	 */
22
	protected $description = 'Full cache rebuild: adds all pages on the site to the static publishing queue';
23
24
	/** @var int - chunk size (set via config) */
25
	private static $records_per_request = 200;
26
27
28
	/**
29
	 * Checks if this task is enabled / disabled via the config setting
30
	 */
31
	public function __construct() {
32
		parent::__construct();
33
		if($this->config()->get('disabled') === true) {
34
			$this->enabled = false;
35
		}
36
	}
37
38
	public function setUrlArrayObject($o) {
39
		$this->urlArrayObject = $o;
40
	}
41
42
	public function getUrlArrayObject() {
43
		return $this->urlArrayObject;
44
	}
45
46
	/**
47
	 *
48
	 * @param SS_HTTPRequest $request
49
	 * @return bool
50
	 */
51
	public function run($request) {
52
53
		if($request->getVar('urls') && is_array($request->getVar('urls'))) {
54
			return $this->queueURLs($request->getVar('urls'));
55
		}
56
		if($request->getVar('urls')) {
57
			return $this->queueURLs(explode(',', $request->getVar('urls')));
58
		}
59
60
		// The following shenanigans are necessary because a simple Page::get()
61
		// will run out of memory on large data sets. This will take the pages
62
		// in chunks by running this script multiple times and setting $_GET['start'].
63
		// Chunk size can be set via yml (SiteTreeFullBuildEngine.records_per_request).
64
		// To disable this functionality, just set a large chunk size and pass start=0.
65
		increase_time_limit_to();
66
		$self = get_class($this);
67
		$verbose = isset($_GET['verbose']);
68
69
		if (isset($_GET['start'])) {
70
			$this->runFrom((int)$_GET['start']);
71
		} else {
72
			foreach(array('framework','sapphire') as $dirname) {
73
				$script = sprintf("%s%s$dirname%scli-script.php", BASE_PATH, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR);
74
				if (file_exists($script)) break;
75
			}
76
77
			$total = $this->getAllLivePages()->count();
78
			echo "Adding all pages to the queue. Total: $total\n\n";
79
			for ($offset = 0; $offset < $total; $offset += self::config()->records_per_request) {
80
				echo "$offset..";
81
				$cmd = "php $script dev/tasks/$self start=$offset";
0 ignored issues
show
Bug introduced by
The variable $script does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
82
				if($verbose) echo "\n  Running '$cmd'\n";
83
				$res = $verbose ? passthru($cmd) : `$cmd`;
84
				if($verbose) echo "  ".preg_replace('/\r\n|\n/', '$0  ', $res)."\n";
85
			}
86
		}
87
	}
88
89
90
	/**
91
	 * Process a chunk of pages
92
	 * @param $start
93
	 */
94
	protected function runFrom($start) {
95
		$chunkSize = (int)self::config()->records_per_request;
96
		$pages = $this->getAllLivePages()->sort('ID')->limit($chunkSize, $start);
97
		$count = 0;
98
99
		$arrNonCachedPages = array();
100
101
		// Collect all URLs into the queue
102
		foreach($pages as $page) {
103
104
			if (is_callable(array($page, 'canCache')) && !$page->canCache()) {
105
				$arrNonCachedPages[] = $page;
106
				continue;
107
			}
108
109
			if (is_callable(array($page, 'urlsToCache'))) {
110
				$this->getUrlArrayObject()->addUrlsOnBehalf($page->urlsToCache(), $page);
111
				$count++;
112
			}
113
		}
114
115
		$publisher = singleton('SiteTree')->getExtensionInstance('FilesystemPublisher');
116
		if ($publisher) {
117
			foreach ($arrNonCachedPages as $page) {
118
				$pathsArray = $publisher->urlsToPaths(array($page->Link()));
119
				$filePath = $publisher->getDestDir() . '/' . array_shift($pathsArray);
120
				@unlink($filePath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
121
				$staleFilepath = str_replace(pathinfo($filePath, PATHINFO_EXTENSION), 'stale.html', $filePath);
122
				@unlink($staleFilepath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
123
			}
124
		}
125
126
		echo sprintf("SiteTreeFullBuildEngine: Queuing %d pages".PHP_EOL, $count);
127
	}
128
129
130
	/**
131
	 * Adds an array of urls to the Queue
132
	 *
133
	 * @param array $urls
134
	 * @return bool - if any pages were queued
135
	 */
136
	protected function queueURLs($urls = array()) {
137
		echo sprintf("SiteTreeFullBuildEngine: Queuing %d pages".PHP_EOL, count($urls));
138
		if(!count($urls)) {
139
			return false;
140
		}
141
		$this->getUrlArrayObject()->addUrls($urls);
142
		return true;
143
	}
144
145
	/**
146
	 *
147
	 * @return DataList
148
	 */
149
	protected function getAllLivePages() {
150
		ini_set('memory_limit', '512M');
151
		$oldMode = Versioned::get_reading_mode();
152
		if(class_exists('Subsite')) {
153
			Subsite::disable_subsite_filter(true);
154
		}
155
		if(class_exists('Translatable')) {
156
			Translatable::disable_locale_filter();
157
		}
158
		Versioned::reading_stage('Live');
159
		$pages = DataObject::get("SiteTree");
160
		Versioned::set_reading_mode($oldMode);
161
		return $pages;
162
	}
163
164
}
165