GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( e54387...b62a26 )
by Lonnie
10s
created
myth/Cron/CronTask.php 1 patch
Indentation   +291 added lines, -291 removed lines patch added patch discarded remove patch
@@ -45,301 +45,301 @@
 block discarded – undo
45 45
  */
46 46
 class CronTask {
47 47
 
48
-    /**
49
-     * The original scheduled string.
50
-     * Any valid relative time string.
51
-     * http://php.net/manual/en/datetime.formats.relative.php
52
-     *
53
-     * @var
54
-     */
55
-    protected $schedule;
56
-
57
-    /**
58
-     * Stores the callable or library name:method to run.
59
-     *
60
-     * @var
61
-     */
62
-    protected $task;
63
-
64
-    //--------------------------------------------------------------------
65
-
66
-    /**
67
-     * Stores our scheduled string and actual task.
68
-     *
69
-     * @param $schedule
70
-     * @param callable $task
71
-     */
72
-    public function __construct($schedule, $task)
73
-    {
74
-        $this->schedule = $schedule;
75
-
76
-        // If $task is not callable, it should be a library:method
77
-        // string that we can parse. But it must have the colon in the string.
78
-        if (! is_callable($task) && strpos($task, ':') === false)
79
-        {
80
-            throw new \RuntimeException( lang('cron.invalid_task') );
81
-        }
82
-
83
-        $this->task = $task;
84
-    }
85
-
86
-    //--------------------------------------------------------------------
87
-
88
-    /**
89
-     * Calculates the next date this task is supposed to run.
90
-     *
91
-     * @param int|'now' $current_time
92
-     *
93
-     * @return timestamp|null
94
-     */
95
-    public function nextRunDate($current_time='now')
96
-    {
97
-        $current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
98
-
99
-        $scheduleType = $this->determineScheduleType($this->schedule);
100
-
101
-        switch ($scheduleType)
102
-        {
103
-            case 'time':
104
-                return $this->findDateInterval($this->schedule, 'next', $current_time);
105
-                break;
106
-            case 'ordinal':
107
-                return strtotime($this->schedule, $current_time);
108
-                break;
109
-            case 'increment':
110
-                return strtotime($this->schedule, $current_time);
111
-                break;
112
-        }
113
-
114
-        return null;
115
-    }
48
+	/**
49
+	 * The original scheduled string.
50
+	 * Any valid relative time string.
51
+	 * http://php.net/manual/en/datetime.formats.relative.php
52
+	 *
53
+	 * @var
54
+	 */
55
+	protected $schedule;
56
+
57
+	/**
58
+	 * Stores the callable or library name:method to run.
59
+	 *
60
+	 * @var
61
+	 */
62
+	protected $task;
63
+
64
+	//--------------------------------------------------------------------
65
+
66
+	/**
67
+	 * Stores our scheduled string and actual task.
68
+	 *
69
+	 * @param $schedule
70
+	 * @param callable $task
71
+	 */
72
+	public function __construct($schedule, $task)
73
+	{
74
+		$this->schedule = $schedule;
75
+
76
+		// If $task is not callable, it should be a library:method
77
+		// string that we can parse. But it must have the colon in the string.
78
+		if (! is_callable($task) && strpos($task, ':') === false)
79
+		{
80
+			throw new \RuntimeException( lang('cron.invalid_task') );
81
+		}
82
+
83
+		$this->task = $task;
84
+	}
85
+
86
+	//--------------------------------------------------------------------
87
+
88
+	/**
89
+	 * Calculates the next date this task is supposed to run.
90
+	 *
91
+	 * @param int|'now' $current_time
92
+	 *
93
+	 * @return timestamp|null
94
+	 */
95
+	public function nextRunDate($current_time='now')
96
+	{
97
+		$current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
98
+
99
+		$scheduleType = $this->determineScheduleType($this->schedule);
100
+
101
+		switch ($scheduleType)
102
+		{
103
+			case 'time':
104
+				return $this->findDateInterval($this->schedule, 'next', $current_time);
105
+				break;
106
+			case 'ordinal':
107
+				return strtotime($this->schedule, $current_time);
108
+				break;
109
+			case 'increment':
110
+				return strtotime($this->schedule, $current_time);
111
+				break;
112
+		}
113
+
114
+		return null;
115
+	}
116 116
     
117
-    //--------------------------------------------------------------------
118
-
119
-    /**
120
-     * Calculates the last time the task should have ran.
121
-     *
122
-     * @param int|'now' $current_time
123
-     *
124
-     * @return timestamp|null
125
-     */
126
-    public function previousRunDate($current_time='now')
127
-    {
128
-        $current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
129
-
130
-        $scheduleType = $this->determineScheduleType($this->schedule);
131
-
132
-        switch ($scheduleType)
133
-        {
134
-            case 'time':
135
-                return $this->findDateInterval($this->schedule, 'prev', $current_time);
136
-                break;
137
-            case 'ordinal':
138
-                return $this->findPreviousOrdinal($this->schedule, $current_time);
139
-                break;
140
-            case 'increment':
141
-                return strtotime('-1 '. $this->schedule, $current_time);
142
-                break;
143
-        }
144
-
145
-        return null;
146
-    }
147
-
148
-    //--------------------------------------------------------------------
149
-
150
-    /**
151
-     * Determines if the task is due to be run now.
152
-     *
153
-     * @param string $current_time
154
-     * @internal param $ int|'now' $current_time
155
-     *
156
-     * @return bool
157
-     */
158
-    public function isDue($current_time='now')
159
-    {
160
-        $current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
161
-
162
-        // For easier matching, and I can't imagine people needing cronjob
163
-        // accuracy to the seconds, we'll just take the current minute.
164
-        return date('Y-m-d H:i', $current_time) == date('Y-m-d H:i', $this->nextRunDate($current_time) );
165
-    }
117
+	//--------------------------------------------------------------------
118
+
119
+	/**
120
+	 * Calculates the last time the task should have ran.
121
+	 *
122
+	 * @param int|'now' $current_time
123
+	 *
124
+	 * @return timestamp|null
125
+	 */
126
+	public function previousRunDate($current_time='now')
127
+	{
128
+		$current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
129
+
130
+		$scheduleType = $this->determineScheduleType($this->schedule);
131
+
132
+		switch ($scheduleType)
133
+		{
134
+			case 'time':
135
+				return $this->findDateInterval($this->schedule, 'prev', $current_time);
136
+				break;
137
+			case 'ordinal':
138
+				return $this->findPreviousOrdinal($this->schedule, $current_time);
139
+				break;
140
+			case 'increment':
141
+				return strtotime('-1 '. $this->schedule, $current_time);
142
+				break;
143
+		}
144
+
145
+		return null;
146
+	}
147
+
148
+	//--------------------------------------------------------------------
149
+
150
+	/**
151
+	 * Determines if the task is due to be run now.
152
+	 *
153
+	 * @param string $current_time
154
+	 * @internal param $ int|'now' $current_time
155
+	 *
156
+	 * @return bool
157
+	 */
158
+	public function isDue($current_time='now')
159
+	{
160
+		$current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
161
+
162
+		// For easier matching, and I can't imagine people needing cronjob
163
+		// accuracy to the seconds, we'll just take the current minute.
164
+		return date('Y-m-d H:i', $current_time) == date('Y-m-d H:i', $this->nextRunDate($current_time) );
165
+	}
166 166
     
167
-    //--------------------------------------------------------------------
168
-
169
-    /**
170
-     * Formats the timestamp produced by nextRunDate and previousRunDate
171
-     * into any format available to date.
172
-     *
173
-     * @param $format_string
174
-     * @return bool|string
175
-     */
176
-    public function format($format_string)
177
-    {
178
-        return date($format_string, strtotime($this->schedule));
179
-    }
180
-
181
-    //--------------------------------------------------------------------
182
-
183
-    /**
184
-     * Gets the associated task.
185
-     *
186
-     * return callable|string
187
-     */
188
-    public function task()
189
-    {
190
-        return $this->task;
191
-    }
192
-
193
-    //--------------------------------------------------------------------
194
-
195
-    /**
196
-     * Gets the original schedule string.
197
-     */
198
-    public function schedule()
199
-    {
200
-        return $this->schedule;
201
-    }
202
-
203
-    //--------------------------------------------------------------------
204
-
205
-    /**
206
-     * Checks the schedule text and determines how we have to treat
207
-     * the schedule when determining next and previous values.
208
-     *
209
-     * Potential Types are:
210
-     *
211
-     *  - increment         Can simply add a +x/-x to the front to get the value.
212
-     *  - time              Something like "every 5 minutes"
213
-     *  - ordinal           Like "first", "second", etc.
214
-     *
215
-     * @param $schedule
216
-     * @return null|string
217
-     */
218
-    public function determineScheduleType($schedule)
219
-    {
220
-        $incs = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sun', 'mon', 'tue',
221
-                'wed', 'thu', 'fri', 'sat', 'weekday', 'weekdays', 'midnight', 'noon'];
222
-        $bigger_incs = [ 'back of', 'front of', 'first day of', 'last day of'];
223
-        $ordinals = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth'];
224
-        $schedule = trim( strtolower($schedule) );
225
-
226
-        $multiple_words = strpos($schedule, ' ');
227
-        $first_word = substr($schedule, 0, $multiple_words ? $multiple_words : strlen($schedule));
228
-
229
-        // Is the first character a number? Then it's a time
230
-        if ( is_numeric( $first_word ) )
231
-        {
232
-            return 'time';
233
-        }
234
-
235
-
236
-        // First, try the shorter increments. We do increments in
237
-        // two passes becuase this should be faster than the loop.
238
-        if (in_array($first_word, $incs))
239
-        {
240
-            return 'increment';
241
-        }
242
-
243
-        // But we have to loop before checking ordinals since
244
-        // ordinals may have same first word as these phrases.
245
-        foreach ($bigger_incs as $test)
246
-        {
247
-            if (strpos($schedule, $test) === 0)
248
-            {
249
-                return 'increment';
250
-            }
251
-        }
252
-
253
-        if (in_array($first_word, $ordinals))
254
-        {
255
-            return 'ordinal';
256
-        }
257
-
258
-        return null;
259
-    }
260
-
261
-    //--------------------------------------------------------------------
262
-
263
-    /**
264
-     * Determines the correct time for 'time' type intervals where
265
-     * the timestamp is expected to happen every 'x period', like
266
-     * 'every 5 minutes', every 3 days, etc.
267
-     *
268
-     * @param $schedule
269
-     * @param $type
270
-     * @return float|int|null
271
-     */
272
-    public function findDateInterval($schedule, $type, $current_time='now')
273
-    {
274
-        $current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
167
+	//--------------------------------------------------------------------
168
+
169
+	/**
170
+	 * Formats the timestamp produced by nextRunDate and previousRunDate
171
+	 * into any format available to date.
172
+	 *
173
+	 * @param $format_string
174
+	 * @return bool|string
175
+	 */
176
+	public function format($format_string)
177
+	{
178
+		return date($format_string, strtotime($this->schedule));
179
+	}
180
+
181
+	//--------------------------------------------------------------------
182
+
183
+	/**
184
+	 * Gets the associated task.
185
+	 *
186
+	 * return callable|string
187
+	 */
188
+	public function task()
189
+	{
190
+		return $this->task;
191
+	}
192
+
193
+	//--------------------------------------------------------------------
194
+
195
+	/**
196
+	 * Gets the original schedule string.
197
+	 */
198
+	public function schedule()
199
+	{
200
+		return $this->schedule;
201
+	}
202
+
203
+	//--------------------------------------------------------------------
204
+
205
+	/**
206
+	 * Checks the schedule text and determines how we have to treat
207
+	 * the schedule when determining next and previous values.
208
+	 *
209
+	 * Potential Types are:
210
+	 *
211
+	 *  - increment         Can simply add a +x/-x to the front to get the value.
212
+	 *  - time              Something like "every 5 minutes"
213
+	 *  - ordinal           Like "first", "second", etc.
214
+	 *
215
+	 * @param $schedule
216
+	 * @return null|string
217
+	 */
218
+	public function determineScheduleType($schedule)
219
+	{
220
+		$incs = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sun', 'mon', 'tue',
221
+				'wed', 'thu', 'fri', 'sat', 'weekday', 'weekdays', 'midnight', 'noon'];
222
+		$bigger_incs = [ 'back of', 'front of', 'first day of', 'last day of'];
223
+		$ordinals = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth'];
224
+		$schedule = trim( strtolower($schedule) );
225
+
226
+		$multiple_words = strpos($schedule, ' ');
227
+		$first_word = substr($schedule, 0, $multiple_words ? $multiple_words : strlen($schedule));
228
+
229
+		// Is the first character a number? Then it's a time
230
+		if ( is_numeric( $first_word ) )
231
+		{
232
+			return 'time';
233
+		}
234
+
235
+
236
+		// First, try the shorter increments. We do increments in
237
+		// two passes becuase this should be faster than the loop.
238
+		if (in_array($first_word, $incs))
239
+		{
240
+			return 'increment';
241
+		}
242
+
243
+		// But we have to loop before checking ordinals since
244
+		// ordinals may have same first word as these phrases.
245
+		foreach ($bigger_incs as $test)
246
+		{
247
+			if (strpos($schedule, $test) === 0)
248
+			{
249
+				return 'increment';
250
+			}
251
+		}
252
+
253
+		if (in_array($first_word, $ordinals))
254
+		{
255
+			return 'ordinal';
256
+		}
257
+
258
+		return null;
259
+	}
260
+
261
+	//--------------------------------------------------------------------
262
+
263
+	/**
264
+	 * Determines the correct time for 'time' type intervals where
265
+	 * the timestamp is expected to happen every 'x period', like
266
+	 * 'every 5 minutes', every 3 days, etc.
267
+	 *
268
+	 * @param $schedule
269
+	 * @param $type
270
+	 * @return float|int|null
271
+	 */
272
+	public function findDateInterval($schedule, $type, $current_time='now')
273
+	{
274
+		$current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
275 275
 
276 276
 //        list($int, $period) = explode(' ', $schedule);
277 277
 
278
-        $diff = strtotime($schedule, $current_time) - $current_time;
279
-
280
-        $return = null;
281
-
282
-        switch ($type)
283
-        {
284
-            case 'next':
285
-                $next = floor($current_time / $diff) * $diff;
286
-
287
-                // Does next already match the current time?
288
-                if (date('Y-m-d H:i', $next) == date('Y-m-d H:i', $current_time))
289
-                {
290
-                    $return = $next;
291
-                }
292
-                else {
293
-                    $return = $next + $diff;
294
-                }
295
-                break;
296
-            case 'prev':
297
-                $next = ceil($current_time / $diff) * $diff;
298
-                $return = $next - $diff;
299
-                break;
300
-        }
301
-
302
-        if (is_numeric($return))
303
-        {
304
-            $return = (int)$return;
305
-        }
306
-
307
-        return $return;
308
-    }
309
-
310
-    //--------------------------------------------------------------------
311
-
312
-    /**
313
-     * Determines the timestamp of the previous ordinal-based time, like
314
-     * 'second Monday'.
315
-     *
316
-     * @param $schedule
317
-     * @param string $current_time
318
-     * @return int|null
319
-     */
320
-    public function findPreviousOrdinal($schedule, $current_time='now')
321
-    {
322
-        $current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
323
-
324
-        if (empty($schedule)) return null;
325
-
326
-        // Loop through months in reverse, checking each one to
327
-        // see if the ordinal is in the past. If so - wer'e done.
328
-        foreach ([0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12] as $i)
329
-        {
330
-            $lastmonth = strtotime("last day of {$i} month", $current_time);
331
-
332
-            $test = strtotime($schedule, $lastmonth);
333
-
334
-            if ($test <= $current_time)
335
-            {
336
-                return $test;
337
-            }
338
-        }
339
-
340
-        return null;
341
-    }
342
-
343
-    //--------------------------------------------------------------------
278
+		$diff = strtotime($schedule, $current_time) - $current_time;
279
+
280
+		$return = null;
281
+
282
+		switch ($type)
283
+		{
284
+			case 'next':
285
+				$next = floor($current_time / $diff) * $diff;
286
+
287
+				// Does next already match the current time?
288
+				if (date('Y-m-d H:i', $next) == date('Y-m-d H:i', $current_time))
289
+				{
290
+					$return = $next;
291
+				}
292
+				else {
293
+					$return = $next + $diff;
294
+				}
295
+				break;
296
+			case 'prev':
297
+				$next = ceil($current_time / $diff) * $diff;
298
+				$return = $next - $diff;
299
+				break;
300
+		}
301
+
302
+		if (is_numeric($return))
303
+		{
304
+			$return = (int)$return;
305
+		}
306
+
307
+		return $return;
308
+	}
309
+
310
+	//--------------------------------------------------------------------
311
+
312
+	/**
313
+	 * Determines the timestamp of the previous ordinal-based time, like
314
+	 * 'second Monday'.
315
+	 *
316
+	 * @param $schedule
317
+	 * @param string $current_time
318
+	 * @return int|null
319
+	 */
320
+	public function findPreviousOrdinal($schedule, $current_time='now')
321
+	{
322
+		$current_time = is_numeric($current_time) ? (int)$current_time : strtotime($current_time);
323
+
324
+		if (empty($schedule)) return null;
325
+
326
+		// Loop through months in reverse, checking each one to
327
+		// see if the ordinal is in the past. If so - wer'e done.
328
+		foreach ([0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12] as $i)
329
+		{
330
+			$lastmonth = strtotime("last day of {$i} month", $current_time);
331
+
332
+			$test = strtotime($schedule, $lastmonth);
333
+
334
+			if ($test <= $current_time)
335
+			{
336
+				return $test;
337
+			}
338
+		}
339
+
340
+		return null;
341
+	}
342
+
343
+	//--------------------------------------------------------------------
344 344
 
345 345
 }
Please login to merge, or discard this patch.
myth/Docs/Builder.php 1 patch
Indentation   +718 added lines, -718 removed lines patch added patch discarded remove patch
@@ -60,725 +60,725 @@
 block discarded – undo
60 60
 class Builder implements DocBuilderInterface
61 61
 {
62 62
 
63
-    protected $docs_ext = '.md';
64
-
65
-    protected $ignore_files = ['_404.md'];
66
-
67
-    protected $doc_folders = [];
68
-
69
-    /**
70
-     * Stores the current folder alias,
71
-     * once the file has been found.
72
-     *
73
-     * @var null
74
-     */
75
-    protected $current_folder = null;
76
-
77
-    protected $table_classes = 'table table-hover';
78
-
79
-    protected $apppath = '';
80
-
81
-    protected $formatters = [];
82
-
83
-    protected $page_title = null;
84
-
85
-    //--------------------------------------------------------------------
86
-
87
-    public function __construct($config = array())
88
-    {
89
-        $this->apppath = ! empty($config['apppath']) ? rtrim($config['apppath'], '/') . '/' : '';
90
-    }
91
-
92
-    //--------------------------------------------------------------------
93
-
94
-    public function pageTitle()
95
-    {
96
-        return $this->page_title;
97
-    }
98
-
99
-    //--------------------------------------------------------------------
100
-
101
-
102
-
103
-    /**
104
-     * Does the actual work of reading in and parsing the help file.
105
-     * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
106
-     * it will limit it's search to that single folder. If nothing is passed, it will
107
-     * search through all of the folders in the order they were given to the library,
108
-     * until it finds the first one.
109
-     *
110
-     * @param string $path The 'path' of the file (relative to the docs
111
-     *                                 folder. Usually from the URI)
112
-     * @param string $restrictToFolder (Optional) The folder nickname
113
-     *
114
-     * @return string
115
-     */
116
-    public function readPage($path, $restrictToFolder = null)
117
-    {
118
-        // Clean up our path
119
-        $path = trim($path, '/ ');
120
-
121
-        $content = $this->locateAndReadFile($path, $restrictToFolder);
122
-
123
-        $content = $this->parse($content);
124
-
125
-        return $content;
126
-    }
127
-
128
-    //--------------------------------------------------------------------
129
-
130
-    /**
131
-     * Parses the contents. Currently runs through the Markdown Extended
132
-     * parser to convert to HTML.
133
-     *
134
-     * @param $str
135
-     * @return mixed
136
-     */
137
-    public function parse($str)
138
-    {
139
-        return $this->format($str);
140
-    }
141
-
142
-    //--------------------------------------------------------------------
143
-
144
-    /**
145
-     * Perform a few housekeeping tasks on a page, like rewriting URLs to full
146
-     * URLs, not relative, ensuring they link correctly, etc.
147
-     *
148
-     * @param      $content
149
-     * @param null $site_url
150
-     * @param null $current_url
151
-     * @return string   The post-processed HTML.
152
-     */
153
-    public function postProcess($content, $site_url = null, $current_url = null)
154
-    {
155
-        if (empty($content)) {
156
-            return $content;
157
-        }
158
-
159
-        try {
160
-            $xml = new \SimpleXMLElement('<?xml version="1.0" standalone="yes"?><div>' . $content . '</div>');
161
-        } catch (\Exception $e) {
162
-            // SimpleXML barfed on us, so send back the un-modified content
163
-            return $content;
164
-        }
165
-
166
-        // Prepare some things and cleanup others
167
-        $groups = array_keys($this->doc_folders);
168
-        $site_url = rtrim($site_url, '/') . '/';
169
-        $current_url = rtrim($current_url, '#/');
170
-
171
-        // Try to determine the current_url if one isn't set.
172
-        if (empty($this->current_folder)) {
173
-            $this->current_folder = $this->detectCurrentFolder($current_url, $groups);
174
-        }
175
-
176
-        /*
63
+	protected $docs_ext = '.md';
64
+
65
+	protected $ignore_files = ['_404.md'];
66
+
67
+	protected $doc_folders = [];
68
+
69
+	/**
70
+	 * Stores the current folder alias,
71
+	 * once the file has been found.
72
+	 *
73
+	 * @var null
74
+	 */
75
+	protected $current_folder = null;
76
+
77
+	protected $table_classes = 'table table-hover';
78
+
79
+	protected $apppath = '';
80
+
81
+	protected $formatters = [];
82
+
83
+	protected $page_title = null;
84
+
85
+	//--------------------------------------------------------------------
86
+
87
+	public function __construct($config = array())
88
+	{
89
+		$this->apppath = ! empty($config['apppath']) ? rtrim($config['apppath'], '/') . '/' : '';
90
+	}
91
+
92
+	//--------------------------------------------------------------------
93
+
94
+	public function pageTitle()
95
+	{
96
+		return $this->page_title;
97
+	}
98
+
99
+	//--------------------------------------------------------------------
100
+
101
+
102
+
103
+	/**
104
+	 * Does the actual work of reading in and parsing the help file.
105
+	 * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
106
+	 * it will limit it's search to that single folder. If nothing is passed, it will
107
+	 * search through all of the folders in the order they were given to the library,
108
+	 * until it finds the first one.
109
+	 *
110
+	 * @param string $path The 'path' of the file (relative to the docs
111
+	 *                                 folder. Usually from the URI)
112
+	 * @param string $restrictToFolder (Optional) The folder nickname
113
+	 *
114
+	 * @return string
115
+	 */
116
+	public function readPage($path, $restrictToFolder = null)
117
+	{
118
+		// Clean up our path
119
+		$path = trim($path, '/ ');
120
+
121
+		$content = $this->locateAndReadFile($path, $restrictToFolder);
122
+
123
+		$content = $this->parse($content);
124
+
125
+		return $content;
126
+	}
127
+
128
+	//--------------------------------------------------------------------
129
+
130
+	/**
131
+	 * Parses the contents. Currently runs through the Markdown Extended
132
+	 * parser to convert to HTML.
133
+	 *
134
+	 * @param $str
135
+	 * @return mixed
136
+	 */
137
+	public function parse($str)
138
+	{
139
+		return $this->format($str);
140
+	}
141
+
142
+	//--------------------------------------------------------------------
143
+
144
+	/**
145
+	 * Perform a few housekeeping tasks on a page, like rewriting URLs to full
146
+	 * URLs, not relative, ensuring they link correctly, etc.
147
+	 *
148
+	 * @param      $content
149
+	 * @param null $site_url
150
+	 * @param null $current_url
151
+	 * @return string   The post-processed HTML.
152
+	 */
153
+	public function postProcess($content, $site_url = null, $current_url = null)
154
+	{
155
+		if (empty($content)) {
156
+			return $content;
157
+		}
158
+
159
+		try {
160
+			$xml = new \SimpleXMLElement('<?xml version="1.0" standalone="yes"?><div>' . $content . '</div>');
161
+		} catch (\Exception $e) {
162
+			// SimpleXML barfed on us, so send back the un-modified content
163
+			return $content;
164
+		}
165
+
166
+		// Prepare some things and cleanup others
167
+		$groups = array_keys($this->doc_folders);
168
+		$site_url = rtrim($site_url, '/') . '/';
169
+		$current_url = rtrim($current_url, '#/');
170
+
171
+		// Try to determine the current_url if one isn't set.
172
+		if (empty($this->current_folder)) {
173
+			$this->current_folder = $this->detectCurrentFolder($current_url, $groups);
174
+		}
175
+
176
+		/*
177 177
          * Rewrite the URLs
178 178
          */
179
-        foreach ($xml->xpath('//a') as $link) {
180
-            $link = $this->reformatAnchor($link, $groups, $current_url, $site_url);
181
-        }
182
-
183
-        $content = $xml->asXML();
184
-        $content = trim(str_replace('<?xml version="1.0" standalone="yes"?>', '', $content));
185
-
186
-        // Clean up and style the tables
187
-        $content = str_replace('<table>', '<table class="' . $this->table_classes . '">', $content);
188
-
189
-        return $content;
190
-    }
191
-    //--------------------------------------------------------------------
192
-
193
-    /**
194
-     * Allows users to define the classes that are attached to
195
-     * generated tables.
196
-     *
197
-     * @param null $classes
198
-     * @return $this
199
-     */
200
-    public function setTableClasses($classes = null)
201
-    {
202
-        $this->table_classes = $classes;
203
-
204
-        return $this;
205
-    }
206
-
207
-    //--------------------------------------------------------------------
208
-
209
-    /**
210
-     * Given the contents to render, will build a list of links for the sidebar
211
-     * out of the headings in the file.
212
-     *
213
-     * Note: Will ONLY use h2 and h3 to build the links from.
214
-     *
215
-     * Note: The $content passed in WILL be modified by adding named anchors
216
-     * that match up with the locations.
217
-     *
218
-     * @param string $content The HTML to analyse for headings.
219
-     * @return string
220
-     */
221
-    public function buildDocumentMap(&$content)
222
-    {
223
-        if (empty($content)) {
224
-            return $content;
225
-        }
226
-
227
-        // If $content already has a wrapping <div> and </div> tags, remove them,
228
-        // since we'll replace them just below.
229
-        if (strpos($content, '<div>') === 0) {
230
-            $content = substr($content, 5);
231
-
232
-            // Trailing div also?
233
-            if (substr($content, -6) == '</div>') {
234
-                $content = substr($content, 0, -6);
235
-            }
236
-        }
237
-
238
-        try {
239
-            $xml = new \SimpleXMLElement('<?xml version="1.0" standalone="yes"?><div>' . $content . '</div>');
240
-        } catch (\Exception $e) {
241
-            // SimpleXML barfed on us, so send back the un-modified content
242
-            return [];
243
-        }
244
-
245
-        $map = [];
246
-        list($map, $content) = $this->extractDocMapAndAddAnchors($content, $xml, $map);
247
-
248
-        return $map;
249
-    }
250
-
251
-    //--------------------------------------------------------------------
252
-
253
-    /**
254
-     * Stores the name of the callback method to run to convert the source
255
-     * files to viewable files. By default, this should be used to register
256
-     * a Mardown Extended formatter with the system, but could be used to
257
-     * extend the
258
-     *
259
-     * @param string $callback
260
-     * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
261
-     * @return $this
262
-     */
263
-    public function registerFormatter($callback = null, $cascade = false)
264
-    {
265
-        if (empty($callback)) return;
266
-
267
-        $this->formatters[] = [
268
-            'callable' => $callback,
269
-            'cascade'  => (bool)$cascade
270
-        ];
271
-
272
-        return $this;
273
-    }
274
-
275
-    //--------------------------------------------------------------------
276
-
277
-    /**
278
-     * Runs the text through the registered formatters.
279
-     *
280
-     * @param $str
281
-     * @return mixed
282
-     */
283
-    public function format($str)
284
-    {
285
-        if (! is_array($this->formatters)) return $str;
286
-
287
-        foreach ($this->formatters as $formatter) {
288
-            $method = $formatter['callable'];
289
-            $cascade = $formatter['cascade'];
290
-
291
-            $str = call_user_func($method, $str);
292
-
293
-            if (! $cascade) return $str;
294
-        }
295
-
296
-        return $str;
297
-    }
298
-
299
-    //--------------------------------------------------------------------
300
-
301
-    //--------------------------------------------------------------------
302
-    // Table of Contents methods
303
-    //--------------------------------------------------------------------
304
-
305
-    /**
306
-     * Retrieves the list of files in a folder and preps the name and filename
307
-     * so it's ready for creating the HTML.
308
-     *
309
-     * @param  String $folder The path to the folder to retrieve.
310
-     *
311
-     * @return Array  An associative array @see parse_ini_file for format
312
-     * details.
313
-     */
314
-    public function buildTOC($folder)
315
-    {
316
-        // If the toc file exists in the folder, use it to build the links.
317
-        if (is_file("{$folder}/_toc.ini")) {
318
-            $toc = parse_ini_file("{$folder}/_toc.ini", true);
319
-            return $this->columnizeTOC($toc);
320
-        }
321
-
322
-        // If the toc file does not exist, build the links by listing the files
323
-        // in the directory (and any sub-directories)
324
-        $map = $this->directory_map($folder);
325
-
326
-        // If directory_map can not open the directory or find any files inside
327
-        // the directory, return an empty array.
328
-        if (empty($map)) {
329
-            return [];
330
-        }
331
-
332
-        // If these docs are located in the /application/docs or /bonfire/docs
333
-        // directory, just use $this->current_group for the root.
334
-        // Module docs need $this->current_group and $type.
335
-        $tocRoot = $this->current_folder;
336
-        if ($this->current_folder != strtolower($folder)) {
337
-            $tocRoot .= '/' . strtolower($folder);
338
-        }
339
-
340
-        $toc = [];
341
-        foreach ($map as $files) {
342
-            // If $files isn't an array, then make it one so that all situations
343
-            // may be dealt with cleanly.
344
-            if (! is_array($files)) {
345
-                $files = [$files];
346
-            }
347
-
348
-            foreach ($files as $file) {
349
-                if (in_array($file, $this->ignore_files)) {
350
-                    continue;
351
-                }
352
-
353
-                // The title for the index is the passed $type. Otherwise,
354
-                // build the title from the file's name.
355
-                if (strpos($file, 'index') === false) {
356
-                    $title = str_replace($this->docs_ext, '', $file);
357
-                    $title = str_replace('_', ' ', $title);
358
-                    $title = ucwords($title);
359
-
360
-                    $toc["{$tocRoot}/{$file}"] = $title;
361
-                } else {
362
-                    $toc[$tocRoot] = $type;
363
-                }
364
-            }
365
-        }
366
-
367
-        $toc = $this->columnizeTOC($toc);
368
-
369
-        return $toc;
370
-    }
371
-
372
-    //--------------------------------------------------------------------
373
-
374
-    /**
375
-     * Sorts the passed TOC array into columns of as close to equal length
376
-     * as we can get it.
377
-     *
378
-     * @param $toc
379
-     * @return array
380
-     */
381
-    protected function columnizeTOC($toc)
382
-    {
383
-        $section_count = count($toc);
384
-
385
-        // First - determine the size of each 'section'.
386
-        $sizes = [];
387
-
388
-        foreach ($toc as $section => $chapters) {
389
-            $sizes[] = count($chapters);
390
-        }
391
-
392
-        $column_avg = (int)round(array_sum($sizes) / $section_count);
393
-
394
-        // Split things into 4 columns of approximately equal size.
395
-        // If we only have 4 columns (or less), then make sure to
396
-        // deal with that also.
397
-        $columns = [];
398
-
399
-        $current_column = 0;
400
-        $current_column_count = 0;
401
-        $keys = array_keys($toc);
402
-
403
-        for ($i = 0; $i <= $section_count; $i++) {
404
-            if (! isset($keys[$i])) {
405
-                continue;
406
-            }
407
-
408
-            $section = array_shift($toc);
409
-
410
-            // Can we stay in this column?
411
-            if ($current_column_count <= $column_avg && $section_count > 4) {
412
-                // Don't forget to account for the heading also.
413
-                $current_column_count += count($section) + 1;
414
-            } else {
415
-                $current_column_count = 0;
416
-                $current_column++;
417
-            }
418
-
419
-            $columns[$current_column][$keys[$i]] = $section;
420
-        }
421
-
422
-        return $columns;
423
-    }
424
-
425
-    //--------------------------------------------------------------------
426
-
427
-    //--------------------------------------------------------------------
428
-    // Folder Methods
429
-    //--------------------------------------------------------------------
430
-
431
-    /**
432
-     * Returns the current docFolders array.
433
-     *
434
-     * @return array
435
-     */
436
-    public function docFolders()
437
-    {
438
-        return $this->doc_folders;
439
-    }
440
-
441
-    //--------------------------------------------------------------------
442
-
443
-    /**
444
-     * Registers a path to be used when searching for documentation files.
445
-     *
446
-     * @param $name     A nickname to reference it by later.
447
-     * @param $path     The server path to the folder.
448
-     * @return $this
449
-     */
450
-    public function addDocFolder($name, $path)
451
-    {
452
-        // Standardize the path
453
-        $path = realpath($path) . '/';
454
-
455
-        // realpath will return FALSE if the path doesn't exist
456
-        // or the script doesn't have access to it.
457
-        if (! $path || $path == '/') {
458
-            return $this;
459
-        }
460
-
461
-        $name = strtolower($name);
462
-
463
-        $this->doc_folders[$name] = $path;
464
-
465
-        return $this;
466
-    }
467
-
468
-    //--------------------------------------------------------------------
469
-
470
-    /**
471
-     * Removes a folder from the folders we scan for documentation files
472
-     * within.
473
-     *
474
-     * @param $name
475
-     * @return $this
476
-     */
477
-    public function removeDocFolder($name)
478
-    {
479
-        $name = strtolower($name);
480
-
481
-        if (isset($this->doc_folders[$name])) {
482
-            unset($this->doc_folders[$name]);
483
-        }
484
-
485
-        return $this;
486
-    }
487
-
488
-    //--------------------------------------------------------------------
489
-
490
-    //--------------------------------------------------------------------
491
-    // Private Methods
492
-    //--------------------------------------------------------------------
493
-
494
-    /**
495
-     * Analyzes the passed in current url string and checks against
496
-     * a list of groups to determine what the current group is.
497
-     *
498
-     * @param $current_url
499
-     * @param $groups
500
-     * @return string
501
-     */
502
-    protected function detectCurrentFolder($current_url, $groups = [])
503
-    {
504
-        if (! is_array($groups)) {
505
-            return null;
506
-        }
507
-
508
-        $segments = explode('/', $current_url);
509
-
510
-        // We start from the back of the array since
511
-        // that's most likely to be close to the end.
512
-        $segments = array_reverse($segments);
513
-
514
-        foreach ($segments as $segment) {
515
-            foreach ($groups as $group) {
516
-                if (strtolower($group) == strtolower($segment)) {
517
-                    return $group;
518
-                }
519
-            }
520
-        }
521
-
522
-        // Nothing found?
523
-        return null;
524
-    }
525
-
526
-    //--------------------------------------------------------------------
527
-
528
-    //--------------------------------------------------------------------
529
-    // Private Methods
530
-    //--------------------------------------------------------------------
531
-
532
-    /**
533
-     * Locates the file on disk and reads the contents into a single string.
534
-     *
535
-     * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
536
-     * it will limit it's search to that single folder. If nothing is passed, it will
537
-     * search through all of the folders in the order they were given to the library,
538
-     * until it finds the first one.
539
-     *
540
-     * @param string $path The 'path' of the file (relative to the docs
541
-     *                                 folder. Usually from the URI)
542
-     * @param string $restrictToFolder (Optional) The nickname of one of the
543
-     *                                 folders to restrict the search to.
544
-     *
545
-     * @throws RuntimeException
546
-     * @return null|string
547
-     */
548
-    private function locateAndReadFile($path, $restrictToFolder = null)
549
-    {
550
-        $folders = $this->doc_folders;
551
-
552
-        if (! is_null($restrictToFolder)) {
553
-            // Make sure the folder exists
554
-            if (! is_null($restrictToFolder) && ! isset($this->doc_folders[$restrictToFolder])) {
555
-                throw new \RuntimeException('You must add the docs folder that you wish to find docs from.');
556
-            }
557
-
558
-            $folders = [$this->doc_folders[$restrictToFolder]];
559
-        }
560
-
561
-        foreach ($folders as $alias => $folder) {
562
-            if (file_exists($folder . $path . $this->docs_ext)) {
563
-                // Store the alias so we know which folder we're in.
564
-                $this->current_folder = $alias;
565
-
566
-                return file_get_contents($folder . $path . $this->docs_ext);
567
-            }
568
-        }
569
-
570
-        return null;
571
-    }
572
-
573
-    //--------------------------------------------------------------------
574
-
575
-    /**
576
-     * Re-formats the passed in link.
577
-     *
578
-     * @param $link
579
-     * @param $current_url
580
-     * @param $site_url
581
-     * @return mixed
582
-     */
583
-    private function reformatAnchor($link, $groups, $current_url, $site_url)
584
-    {
585
-        // Grab the href value.
586
-        $href = $link->attributes()->href;
587
-
588
-        // If the href is null, it's probably a named anchor with no content.
589
-        if (! $href) {
590
-            // Make sure it has an href, else the XML will not close this
591
-            // tag correctly.
592
-            $link['href'] = ' ';
593
-
594
-            return $link;
595
-        }
596
-
597
-        // Remove any trailing # signs
598
-        $href = rtrim($href, '# ');
599
-
600
-        // If the href starts with #, then attach the current_url to it
601
-        if ($href != '' && substr_compare($href, '#', 0, 1) === 0) {
602
-            $link['href'] = $current_url . $href;
603
-
604
-            return $link;
605
-        }
606
-
607
-        // If it's a full external path, go on...
608
-        if ((strpos($href, 'http://') !== false || strpos($href, 'https://') !== false) &&
609
-            strpos($href, $site_url) === false
610
-        ) {
611
-            $link['target'] = "_blank";
612
-            return $link;
613
-        }
614
-
615
-        // If it's a full local path, get rid of it.
616
-        if (strpos($href, $site_url) !== false) {
617
-            $href = str_replace($site_url, '', $href);
618
-        }
619
-
620
-        // Strip out some unnecessary items, just in case they're there.
621
-        if (substr($href, 0, strlen('docs/')) == 'docs/') {
622
-            $href = substr($href, strlen('docs/'));
623
-        }
624
-
625
-        // This includes 'bonfire/' if it was missed during the conversion.
626
-        if (substr($href, 0, strlen('bonfire/')) == 'bonfire/') {
627
-            $href = substr($href, strlen('bonfire/'));
628
-        }
629
-
630
-        // If another 'group' is not already defined at the head of the link
631
-        // then add the current group to it.
632
-        $group_found = false;
633
-
634
-        foreach ($groups as $group) {
635
-            if (strpos($href, $group) === 0) {
636
-                $group_found = true;
637
-            }
638
-        }
639
-
640
-        if (! $group_found) {
641
-            $href = $this->current_folder . '/' . $href;
642
-        }
643
-
644
-        // Convert to full site_url
645
-        if (strpos($href, 'http') !== 0) {
646
-            $href = $site_url . 'docs/' . ltrim($href, '/ ');
647
-        }
648
-
649
-        // Save the corrected href
650
-        $link['href'] = $href;
651
-
652
-        return $link;
653
-    }
654
-
655
-    //--------------------------------------------------------------------
656
-
657
-    /**
658
-     * Creates a Document Map based on <h2> and <h3> tags.
659
-     * Also adds named anchors into the $content so the map
660
-     * can link to the content properly.
661
-     *
662
-     * @param $content
663
-     * @param $xml
664
-     * @param $map
665
-     * @return array
666
-     */
667
-    protected function extractDocMapAndAddAnchors(&$content, $xml, $map)
668
-    {
669
-        // Holds the current h2 we're processing
670
-        $current_obj = [];
671
-
672
-        $currentChild = 0;
673
-
674
-        foreach ($xml->children() as $childType => $line) {
675
-            $currentChild++;
676
-
677
-            // If it's an h1 - take the first and make it
678
-            // our page title.
679
-            if ($childType == 'h1' && empty($this->page_title))
680
-            {
681
-                $this->page_title = (string)$line;
682
-            }
683
-
684
-            // Make sure that our current object is
685
-            // stored and reset.
686
-            if ($childType == 'h1' || $childType == 'h2') {
687
-                if (count($current_obj)) {
688
-                    $map[] = $current_obj;
689
-                    $current_obj = [];
690
-                }
691
-            }
692
-
693
-            if ($childType == 'h2') {
694
-                $name = (string)$line;
695
-                $link = strtolower(str_replace(' ', '_', (string)$line));
696
-
697
-                $current_obj['name'] = $name;
698
-                $current_obj['link'] = '#' . $link;
699
-                $current_obj['items'] = [];
700
-
701
-                // Insert a named anchor into the $content
702
-                $anchor = '<a name="' . $link . '" id="' . $link . '" ></a>';
703
-
704
-                $search = "<h2>{$name}</h2>";
705
-
706
-                $content = str_replace($search, $anchor . $search, $content);
707
-            } elseif ($childType == 'h3') {
708
-                // Make sure we have some place to store the items.
709
-                if (! isset($current_obj['items'])) {
710
-                    $current_obj['items'] = [];
711
-                }
712
-
713
-                $link = strtolower(str_replace(' ', '_', (string)$line));
714
-                $name = (string)$line;
715
-
716
-                $current_obj['items'][] = [
717
-                    'name' => $name,
718
-                    'link' => '#' . $link
719
-                ];
720
-
721
-                // Insert a named anchor into the $content
722
-                $anchor = '<a name="' . $link . '" id="' . $link . '" ></a>';
723
-
724
-                $search = "<h3>{$name}</h3>";
725
-
726
-                $content = str_replace($search, $anchor . $search, $content);
727
-            }
728
-
729
-            // Is this the last element? Then close out our current object.
730
-            if (count($xml) == $currentChild) {
731
-                if (count($current_obj)) {
732
-                    $map[] = $current_obj;
733
-                }
734
-            }
735
-        }
736
-        return [$map, $content];
737
-    }
738
-    //--------------------------------------------------------------------
739
-
740
-    /**
741
-     * Create a Directory Map
742
-     *
743
-     * Reads the specified directory and builds an array
744
-     * representation of it. Sub-folders contained with the
745
-     * directory will be mapped as well.
746
-     *
747
-     * @param    string $source_dir Path to source
748
-     * @param    int $directory_depth Depth of directories to traverse
749
-     *                        (0 = fully recursive, 1 = current dir, etc)
750
-     * @param    bool $hidden Whether to show hidden files
751
-     * @return    array
752
-     */
753
-    protected function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
754
-    {
755
-        if ($fp = @opendir($source_dir)) {
756
-            $filedata = array();
757
-            $new_depth = $directory_depth - 1;
758
-            $source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
759
-
760
-            while (FALSE !== ($file = readdir($fp))) {
761
-                // Remove '.', '..', and hidden files [optional]
762
-                if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) {
763
-                    continue;
764
-                }
765
-
766
-                is_dir($source_dir . $file) && $file .= DIRECTORY_SEPARATOR;
767
-
768
-                if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file)) {
769
-                    $filedata[$file] = directory_map($source_dir . $file, $new_depth, $hidden);
770
-                } else {
771
-                    $filedata[] = $file;
772
-                }
773
-            }
774
-
775
-            closedir($fp);
776
-            return $filedata;
777
-        }
778
-
779
-        return FALSE;
780
-    }
781
-
782
-    //--------------------------------------------------------------------
179
+		foreach ($xml->xpath('//a') as $link) {
180
+			$link = $this->reformatAnchor($link, $groups, $current_url, $site_url);
181
+		}
182
+
183
+		$content = $xml->asXML();
184
+		$content = trim(str_replace('<?xml version="1.0" standalone="yes"?>', '', $content));
185
+
186
+		// Clean up and style the tables
187
+		$content = str_replace('<table>', '<table class="' . $this->table_classes . '">', $content);
188
+
189
+		return $content;
190
+	}
191
+	//--------------------------------------------------------------------
192
+
193
+	/**
194
+	 * Allows users to define the classes that are attached to
195
+	 * generated tables.
196
+	 *
197
+	 * @param null $classes
198
+	 * @return $this
199
+	 */
200
+	public function setTableClasses($classes = null)
201
+	{
202
+		$this->table_classes = $classes;
203
+
204
+		return $this;
205
+	}
206
+
207
+	//--------------------------------------------------------------------
208
+
209
+	/**
210
+	 * Given the contents to render, will build a list of links for the sidebar
211
+	 * out of the headings in the file.
212
+	 *
213
+	 * Note: Will ONLY use h2 and h3 to build the links from.
214
+	 *
215
+	 * Note: The $content passed in WILL be modified by adding named anchors
216
+	 * that match up with the locations.
217
+	 *
218
+	 * @param string $content The HTML to analyse for headings.
219
+	 * @return string
220
+	 */
221
+	public function buildDocumentMap(&$content)
222
+	{
223
+		if (empty($content)) {
224
+			return $content;
225
+		}
226
+
227
+		// If $content already has a wrapping <div> and </div> tags, remove them,
228
+		// since we'll replace them just below.
229
+		if (strpos($content, '<div>') === 0) {
230
+			$content = substr($content, 5);
231
+
232
+			// Trailing div also?
233
+			if (substr($content, -6) == '</div>') {
234
+				$content = substr($content, 0, -6);
235
+			}
236
+		}
237
+
238
+		try {
239
+			$xml = new \SimpleXMLElement('<?xml version="1.0" standalone="yes"?><div>' . $content . '</div>');
240
+		} catch (\Exception $e) {
241
+			// SimpleXML barfed on us, so send back the un-modified content
242
+			return [];
243
+		}
244
+
245
+		$map = [];
246
+		list($map, $content) = $this->extractDocMapAndAddAnchors($content, $xml, $map);
247
+
248
+		return $map;
249
+	}
250
+
251
+	//--------------------------------------------------------------------
252
+
253
+	/**
254
+	 * Stores the name of the callback method to run to convert the source
255
+	 * files to viewable files. By default, this should be used to register
256
+	 * a Mardown Extended formatter with the system, but could be used to
257
+	 * extend the
258
+	 *
259
+	 * @param string $callback
260
+	 * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
261
+	 * @return $this
262
+	 */
263
+	public function registerFormatter($callback = null, $cascade = false)
264
+	{
265
+		if (empty($callback)) return;
266
+
267
+		$this->formatters[] = [
268
+			'callable' => $callback,
269
+			'cascade'  => (bool)$cascade
270
+		];
271
+
272
+		return $this;
273
+	}
274
+
275
+	//--------------------------------------------------------------------
276
+
277
+	/**
278
+	 * Runs the text through the registered formatters.
279
+	 *
280
+	 * @param $str
281
+	 * @return mixed
282
+	 */
283
+	public function format($str)
284
+	{
285
+		if (! is_array($this->formatters)) return $str;
286
+
287
+		foreach ($this->formatters as $formatter) {
288
+			$method = $formatter['callable'];
289
+			$cascade = $formatter['cascade'];
290
+
291
+			$str = call_user_func($method, $str);
292
+
293
+			if (! $cascade) return $str;
294
+		}
295
+
296
+		return $str;
297
+	}
298
+
299
+	//--------------------------------------------------------------------
300
+
301
+	//--------------------------------------------------------------------
302
+	// Table of Contents methods
303
+	//--------------------------------------------------------------------
304
+
305
+	/**
306
+	 * Retrieves the list of files in a folder and preps the name and filename
307
+	 * so it's ready for creating the HTML.
308
+	 *
309
+	 * @param  String $folder The path to the folder to retrieve.
310
+	 *
311
+	 * @return Array  An associative array @see parse_ini_file for format
312
+	 * details.
313
+	 */
314
+	public function buildTOC($folder)
315
+	{
316
+		// If the toc file exists in the folder, use it to build the links.
317
+		if (is_file("{$folder}/_toc.ini")) {
318
+			$toc = parse_ini_file("{$folder}/_toc.ini", true);
319
+			return $this->columnizeTOC($toc);
320
+		}
321
+
322
+		// If the toc file does not exist, build the links by listing the files
323
+		// in the directory (and any sub-directories)
324
+		$map = $this->directory_map($folder);
325
+
326
+		// If directory_map can not open the directory or find any files inside
327
+		// the directory, return an empty array.
328
+		if (empty($map)) {
329
+			return [];
330
+		}
331
+
332
+		// If these docs are located in the /application/docs or /bonfire/docs
333
+		// directory, just use $this->current_group for the root.
334
+		// Module docs need $this->current_group and $type.
335
+		$tocRoot = $this->current_folder;
336
+		if ($this->current_folder != strtolower($folder)) {
337
+			$tocRoot .= '/' . strtolower($folder);
338
+		}
339
+
340
+		$toc = [];
341
+		foreach ($map as $files) {
342
+			// If $files isn't an array, then make it one so that all situations
343
+			// may be dealt with cleanly.
344
+			if (! is_array($files)) {
345
+				$files = [$files];
346
+			}
347
+
348
+			foreach ($files as $file) {
349
+				if (in_array($file, $this->ignore_files)) {
350
+					continue;
351
+				}
352
+
353
+				// The title for the index is the passed $type. Otherwise,
354
+				// build the title from the file's name.
355
+				if (strpos($file, 'index') === false) {
356
+					$title = str_replace($this->docs_ext, '', $file);
357
+					$title = str_replace('_', ' ', $title);
358
+					$title = ucwords($title);
359
+
360
+					$toc["{$tocRoot}/{$file}"] = $title;
361
+				} else {
362
+					$toc[$tocRoot] = $type;
363
+				}
364
+			}
365
+		}
366
+
367
+		$toc = $this->columnizeTOC($toc);
368
+
369
+		return $toc;
370
+	}
371
+
372
+	//--------------------------------------------------------------------
373
+
374
+	/**
375
+	 * Sorts the passed TOC array into columns of as close to equal length
376
+	 * as we can get it.
377
+	 *
378
+	 * @param $toc
379
+	 * @return array
380
+	 */
381
+	protected function columnizeTOC($toc)
382
+	{
383
+		$section_count = count($toc);
384
+
385
+		// First - determine the size of each 'section'.
386
+		$sizes = [];
387
+
388
+		foreach ($toc as $section => $chapters) {
389
+			$sizes[] = count($chapters);
390
+		}
391
+
392
+		$column_avg = (int)round(array_sum($sizes) / $section_count);
393
+
394
+		// Split things into 4 columns of approximately equal size.
395
+		// If we only have 4 columns (or less), then make sure to
396
+		// deal with that also.
397
+		$columns = [];
398
+
399
+		$current_column = 0;
400
+		$current_column_count = 0;
401
+		$keys = array_keys($toc);
402
+
403
+		for ($i = 0; $i <= $section_count; $i++) {
404
+			if (! isset($keys[$i])) {
405
+				continue;
406
+			}
407
+
408
+			$section = array_shift($toc);
409
+
410
+			// Can we stay in this column?
411
+			if ($current_column_count <= $column_avg && $section_count > 4) {
412
+				// Don't forget to account for the heading also.
413
+				$current_column_count += count($section) + 1;
414
+			} else {
415
+				$current_column_count = 0;
416
+				$current_column++;
417
+			}
418
+
419
+			$columns[$current_column][$keys[$i]] = $section;
420
+		}
421
+
422
+		return $columns;
423
+	}
424
+
425
+	//--------------------------------------------------------------------
426
+
427
+	//--------------------------------------------------------------------
428
+	// Folder Methods
429
+	//--------------------------------------------------------------------
430
+
431
+	/**
432
+	 * Returns the current docFolders array.
433
+	 *
434
+	 * @return array
435
+	 */
436
+	public function docFolders()
437
+	{
438
+		return $this->doc_folders;
439
+	}
440
+
441
+	//--------------------------------------------------------------------
442
+
443
+	/**
444
+	 * Registers a path to be used when searching for documentation files.
445
+	 *
446
+	 * @param $name     A nickname to reference it by later.
447
+	 * @param $path     The server path to the folder.
448
+	 * @return $this
449
+	 */
450
+	public function addDocFolder($name, $path)
451
+	{
452
+		// Standardize the path
453
+		$path = realpath($path) . '/';
454
+
455
+		// realpath will return FALSE if the path doesn't exist
456
+		// or the script doesn't have access to it.
457
+		if (! $path || $path == '/') {
458
+			return $this;
459
+		}
460
+
461
+		$name = strtolower($name);
462
+
463
+		$this->doc_folders[$name] = $path;
464
+
465
+		return $this;
466
+	}
467
+
468
+	//--------------------------------------------------------------------
469
+
470
+	/**
471
+	 * Removes a folder from the folders we scan for documentation files
472
+	 * within.
473
+	 *
474
+	 * @param $name
475
+	 * @return $this
476
+	 */
477
+	public function removeDocFolder($name)
478
+	{
479
+		$name = strtolower($name);
480
+
481
+		if (isset($this->doc_folders[$name])) {
482
+			unset($this->doc_folders[$name]);
483
+		}
484
+
485
+		return $this;
486
+	}
487
+
488
+	//--------------------------------------------------------------------
489
+
490
+	//--------------------------------------------------------------------
491
+	// Private Methods
492
+	//--------------------------------------------------------------------
493
+
494
+	/**
495
+	 * Analyzes the passed in current url string and checks against
496
+	 * a list of groups to determine what the current group is.
497
+	 *
498
+	 * @param $current_url
499
+	 * @param $groups
500
+	 * @return string
501
+	 */
502
+	protected function detectCurrentFolder($current_url, $groups = [])
503
+	{
504
+		if (! is_array($groups)) {
505
+			return null;
506
+		}
507
+
508
+		$segments = explode('/', $current_url);
509
+
510
+		// We start from the back of the array since
511
+		// that's most likely to be close to the end.
512
+		$segments = array_reverse($segments);
513
+
514
+		foreach ($segments as $segment) {
515
+			foreach ($groups as $group) {
516
+				if (strtolower($group) == strtolower($segment)) {
517
+					return $group;
518
+				}
519
+			}
520
+		}
521
+
522
+		// Nothing found?
523
+		return null;
524
+	}
525
+
526
+	//--------------------------------------------------------------------
527
+
528
+	//--------------------------------------------------------------------
529
+	// Private Methods
530
+	//--------------------------------------------------------------------
531
+
532
+	/**
533
+	 * Locates the file on disk and reads the contents into a single string.
534
+	 *
535
+	 * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
536
+	 * it will limit it's search to that single folder. If nothing is passed, it will
537
+	 * search through all of the folders in the order they were given to the library,
538
+	 * until it finds the first one.
539
+	 *
540
+	 * @param string $path The 'path' of the file (relative to the docs
541
+	 *                                 folder. Usually from the URI)
542
+	 * @param string $restrictToFolder (Optional) The nickname of one of the
543
+	 *                                 folders to restrict the search to.
544
+	 *
545
+	 * @throws RuntimeException
546
+	 * @return null|string
547
+	 */
548
+	private function locateAndReadFile($path, $restrictToFolder = null)
549
+	{
550
+		$folders = $this->doc_folders;
551
+
552
+		if (! is_null($restrictToFolder)) {
553
+			// Make sure the folder exists
554
+			if (! is_null($restrictToFolder) && ! isset($this->doc_folders[$restrictToFolder])) {
555
+				throw new \RuntimeException('You must add the docs folder that you wish to find docs from.');
556
+			}
557
+
558
+			$folders = [$this->doc_folders[$restrictToFolder]];
559
+		}
560
+
561
+		foreach ($folders as $alias => $folder) {
562
+			if (file_exists($folder . $path . $this->docs_ext)) {
563
+				// Store the alias so we know which folder we're in.
564
+				$this->current_folder = $alias;
565
+
566
+				return file_get_contents($folder . $path . $this->docs_ext);
567
+			}
568
+		}
569
+
570
+		return null;
571
+	}
572
+
573
+	//--------------------------------------------------------------------
574
+
575
+	/**
576
+	 * Re-formats the passed in link.
577
+	 *
578
+	 * @param $link
579
+	 * @param $current_url
580
+	 * @param $site_url
581
+	 * @return mixed
582
+	 */
583
+	private function reformatAnchor($link, $groups, $current_url, $site_url)
584
+	{
585
+		// Grab the href value.
586
+		$href = $link->attributes()->href;
587
+
588
+		// If the href is null, it's probably a named anchor with no content.
589
+		if (! $href) {
590
+			// Make sure it has an href, else the XML will not close this
591
+			// tag correctly.
592
+			$link['href'] = ' ';
593
+
594
+			return $link;
595
+		}
596
+
597
+		// Remove any trailing # signs
598
+		$href = rtrim($href, '# ');
599
+
600
+		// If the href starts with #, then attach the current_url to it
601
+		if ($href != '' && substr_compare($href, '#', 0, 1) === 0) {
602
+			$link['href'] = $current_url . $href;
603
+
604
+			return $link;
605
+		}
606
+
607
+		// If it's a full external path, go on...
608
+		if ((strpos($href, 'http://') !== false || strpos($href, 'https://') !== false) &&
609
+			strpos($href, $site_url) === false
610
+		) {
611
+			$link['target'] = "_blank";
612
+			return $link;
613
+		}
614
+
615
+		// If it's a full local path, get rid of it.
616
+		if (strpos($href, $site_url) !== false) {
617
+			$href = str_replace($site_url, '', $href);
618
+		}
619
+
620
+		// Strip out some unnecessary items, just in case they're there.
621
+		if (substr($href, 0, strlen('docs/')) == 'docs/') {
622
+			$href = substr($href, strlen('docs/'));
623
+		}
624
+
625
+		// This includes 'bonfire/' if it was missed during the conversion.
626
+		if (substr($href, 0, strlen('bonfire/')) == 'bonfire/') {
627
+			$href = substr($href, strlen('bonfire/'));
628
+		}
629
+
630
+		// If another 'group' is not already defined at the head of the link
631
+		// then add the current group to it.
632
+		$group_found = false;
633
+
634
+		foreach ($groups as $group) {
635
+			if (strpos($href, $group) === 0) {
636
+				$group_found = true;
637
+			}
638
+		}
639
+
640
+		if (! $group_found) {
641
+			$href = $this->current_folder . '/' . $href;
642
+		}
643
+
644
+		// Convert to full site_url
645
+		if (strpos($href, 'http') !== 0) {
646
+			$href = $site_url . 'docs/' . ltrim($href, '/ ');
647
+		}
648
+
649
+		// Save the corrected href
650
+		$link['href'] = $href;
651
+
652
+		return $link;
653
+	}
654
+
655
+	//--------------------------------------------------------------------
656
+
657
+	/**
658
+	 * Creates a Document Map based on <h2> and <h3> tags.
659
+	 * Also adds named anchors into the $content so the map
660
+	 * can link to the content properly.
661
+	 *
662
+	 * @param $content
663
+	 * @param $xml
664
+	 * @param $map
665
+	 * @return array
666
+	 */
667
+	protected function extractDocMapAndAddAnchors(&$content, $xml, $map)
668
+	{
669
+		// Holds the current h2 we're processing
670
+		$current_obj = [];
671
+
672
+		$currentChild = 0;
673
+
674
+		foreach ($xml->children() as $childType => $line) {
675
+			$currentChild++;
676
+
677
+			// If it's an h1 - take the first and make it
678
+			// our page title.
679
+			if ($childType == 'h1' && empty($this->page_title))
680
+			{
681
+				$this->page_title = (string)$line;
682
+			}
683
+
684
+			// Make sure that our current object is
685
+			// stored and reset.
686
+			if ($childType == 'h1' || $childType == 'h2') {
687
+				if (count($current_obj)) {
688
+					$map[] = $current_obj;
689
+					$current_obj = [];
690
+				}
691
+			}
692
+
693
+			if ($childType == 'h2') {
694
+				$name = (string)$line;
695
+				$link = strtolower(str_replace(' ', '_', (string)$line));
696
+
697
+				$current_obj['name'] = $name;
698
+				$current_obj['link'] = '#' . $link;
699
+				$current_obj['items'] = [];
700
+
701
+				// Insert a named anchor into the $content
702
+				$anchor = '<a name="' . $link . '" id="' . $link . '" ></a>';
703
+
704
+				$search = "<h2>{$name}</h2>";
705
+
706
+				$content = str_replace($search, $anchor . $search, $content);
707
+			} elseif ($childType == 'h3') {
708
+				// Make sure we have some place to store the items.
709
+				if (! isset($current_obj['items'])) {
710
+					$current_obj['items'] = [];
711
+				}
712
+
713
+				$link = strtolower(str_replace(' ', '_', (string)$line));
714
+				$name = (string)$line;
715
+
716
+				$current_obj['items'][] = [
717
+					'name' => $name,
718
+					'link' => '#' . $link
719
+				];
720
+
721
+				// Insert a named anchor into the $content
722
+				$anchor = '<a name="' . $link . '" id="' . $link . '" ></a>';
723
+
724
+				$search = "<h3>{$name}</h3>";
725
+
726
+				$content = str_replace($search, $anchor . $search, $content);
727
+			}
728
+
729
+			// Is this the last element? Then close out our current object.
730
+			if (count($xml) == $currentChild) {
731
+				if (count($current_obj)) {
732
+					$map[] = $current_obj;
733
+				}
734
+			}
735
+		}
736
+		return [$map, $content];
737
+	}
738
+	//--------------------------------------------------------------------
739
+
740
+	/**
741
+	 * Create a Directory Map
742
+	 *
743
+	 * Reads the specified directory and builds an array
744
+	 * representation of it. Sub-folders contained with the
745
+	 * directory will be mapped as well.
746
+	 *
747
+	 * @param    string $source_dir Path to source
748
+	 * @param    int $directory_depth Depth of directories to traverse
749
+	 *                        (0 = fully recursive, 1 = current dir, etc)
750
+	 * @param    bool $hidden Whether to show hidden files
751
+	 * @return    array
752
+	 */
753
+	protected function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
754
+	{
755
+		if ($fp = @opendir($source_dir)) {
756
+			$filedata = array();
757
+			$new_depth = $directory_depth - 1;
758
+			$source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
759
+
760
+			while (FALSE !== ($file = readdir($fp))) {
761
+				// Remove '.', '..', and hidden files [optional]
762
+				if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) {
763
+					continue;
764
+				}
765
+
766
+				is_dir($source_dir . $file) && $file .= DIRECTORY_SEPARATOR;
767
+
768
+				if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file)) {
769
+					$filedata[$file] = directory_map($source_dir . $file, $new_depth, $hidden);
770
+				} else {
771
+					$filedata[] = $file;
772
+				}
773
+			}
774
+
775
+			closedir($fp);
776
+			return $filedata;
777
+		}
778
+
779
+		return FALSE;
780
+	}
781
+
782
+	//--------------------------------------------------------------------
783 783
 
784 784
 }
Please login to merge, or discard this patch.
myth/Docs/DocBuilderInterface.php 1 patch
Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -40,117 +40,117 @@
 block discarded – undo
40 40
  */
41 41
 interface DocBuilderInterface
42 42
 {
43
-    /**
44
-     * Does the actual work of reading in and parsing the help file.
45
-     * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
46
-     * it will limit it's search to that single folder. If nothing is passed, it will
47
-     * search through all of the folders in the order they were given to the library,
48
-     * until it finds the first one.
49
-     *
50
-     * @param string $path The 'path' of the file (relative to the docs
51
-     *                                 folder. Usually from the URI)
52
-     * @param string $restrictToFolder (Optional) The folder nickname
53
-     *
54
-     * @return string
55
-     */
56
-    public function readPage($path, $restrictToFolder = null);
43
+	/**
44
+	 * Does the actual work of reading in and parsing the help file.
45
+	 * If a folder Nickname (see addDocFolder() ) is passed as the second parameter,
46
+	 * it will limit it's search to that single folder. If nothing is passed, it will
47
+	 * search through all of the folders in the order they were given to the library,
48
+	 * until it finds the first one.
49
+	 *
50
+	 * @param string $path The 'path' of the file (relative to the docs
51
+	 *                                 folder. Usually from the URI)
52
+	 * @param string $restrictToFolder (Optional) The folder nickname
53
+	 *
54
+	 * @return string
55
+	 */
56
+	public function readPage($path, $restrictToFolder = null);
57 57
 
58
-    /**
59
-     * Parses the contents. Currently runs through the Markdown Extended
60
-     * parser to convert to HTML.
61
-     *
62
-     * @param $str
63
-     * @return mixed
64
-     */
65
-    public function parse($str);
58
+	/**
59
+	 * Parses the contents. Currently runs through the Markdown Extended
60
+	 * parser to convert to HTML.
61
+	 *
62
+	 * @param $str
63
+	 * @return mixed
64
+	 */
65
+	public function parse($str);
66 66
 
67
-    /**
68
-     * Perform a few housekeeping tasks on a page, like rewriting URLs to full
69
-     * URLs, not relative, ensuring they link correctly, etc.
70
-     *
71
-     * @param      $content
72
-     * @param null $site_url
73
-     * @param null $current_url
74
-     * @return string   The post-processed HTML.
75
-     */
76
-    public function postProcess($content, $site_url = null, $current_url = null);
67
+	/**
68
+	 * Perform a few housekeeping tasks on a page, like rewriting URLs to full
69
+	 * URLs, not relative, ensuring they link correctly, etc.
70
+	 *
71
+	 * @param      $content
72
+	 * @param null $site_url
73
+	 * @param null $current_url
74
+	 * @return string   The post-processed HTML.
75
+	 */
76
+	public function postProcess($content, $site_url = null, $current_url = null);
77 77
 
78
-    /**
79
-     * Allows users to define the classes that are attached to
80
-     * generated tables.
81
-     *
82
-     * @param null $classes
83
-     * @return $this
84
-     */
85
-    public function setTableClasses($classes = null);
78
+	/**
79
+	 * Allows users to define the classes that are attached to
80
+	 * generated tables.
81
+	 *
82
+	 * @param null $classes
83
+	 * @return $this
84
+	 */
85
+	public function setTableClasses($classes = null);
86 86
 
87
-    /**
88
-     * Given the contents to render, will build a list of links for the sidebar
89
-     * out of the headings in the file.
90
-     *
91
-     * Note: Will ONLY use h2 and h3 to build the links from.
92
-     *
93
-     * Note: The $content passed in WILL be modified by adding named anchors
94
-     * that match up with the locations.
95
-     *
96
-     * @param string $content The HTML to analyse for headings.
97
-     * @return string
98
-     */
99
-    public function buildDocumentMap(&$content);
87
+	/**
88
+	 * Given the contents to render, will build a list of links for the sidebar
89
+	 * out of the headings in the file.
90
+	 *
91
+	 * Note: Will ONLY use h2 and h3 to build the links from.
92
+	 *
93
+	 * Note: The $content passed in WILL be modified by adding named anchors
94
+	 * that match up with the locations.
95
+	 *
96
+	 * @param string $content The HTML to analyse for headings.
97
+	 * @return string
98
+	 */
99
+	public function buildDocumentMap(&$content);
100 100
 
101
-    /**
102
-     * Stores the name of the callback method to run to convert the source
103
-     * files to viewable files. By default, this should be used to register
104
-     * a Mardown Extended formatter with the system, but could be used to
105
-     * extend the
106
-     *
107
-     * @param string $callback_name
108
-     * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
109
-     * @return $this
110
-     */
111
-    public function registerFormatter($callback_name = '', $cascade = false);
101
+	/**
102
+	 * Stores the name of the callback method to run to convert the source
103
+	 * files to viewable files. By default, this should be used to register
104
+	 * a Mardown Extended formatter with the system, but could be used to
105
+	 * extend the
106
+	 *
107
+	 * @param string $callback_name
108
+	 * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
109
+	 * @return $this
110
+	 */
111
+	public function registerFormatter($callback_name = '', $cascade = false);
112 112
 
113
-    /**
114
-     * Runs the text through the registered formatters.
115
-     *
116
-     * @param $str
117
-     * @return mixed
118
-     */
119
-    public function format($str);
113
+	/**
114
+	 * Runs the text through the registered formatters.
115
+	 *
116
+	 * @param $str
117
+	 * @return mixed
118
+	 */
119
+	public function format($str);
120 120
 
121
-    /**
122
-     * Retrieves the list of files in a folder and preps the name and filename
123
-     * so it's ready for creating the HTML.
124
-     *
125
-     * @param  String $folder The path to the folder to retrieve.
126
-     *
127
-     * @return Array  An associative array @see parse_ini_file for format
128
-     * details.
129
-     */
130
-    public function buildTOC($folder);
121
+	/**
122
+	 * Retrieves the list of files in a folder and preps the name and filename
123
+	 * so it's ready for creating the HTML.
124
+	 *
125
+	 * @param  String $folder The path to the folder to retrieve.
126
+	 *
127
+	 * @return Array  An associative array @see parse_ini_file for format
128
+	 * details.
129
+	 */
130
+	public function buildTOC($folder);
131 131
 
132
-    /**
133
-     * Returns the current docFolders array.
134
-     *
135
-     * @return array
136
-     */
137
-    public function docFolders();
132
+	/**
133
+	 * Returns the current docFolders array.
134
+	 *
135
+	 * @return array
136
+	 */
137
+	public function docFolders();
138 138
 
139
-    /**
140
-     * Registers a path to be used when searching for documentation files.
141
-     *
142
-     * @param $name     A nickname to reference it by later.
143
-     * @param $path     The server path to the folder.
144
-     * @return $this
145
-     */
146
-    public function addDocFolder($name, $path);
139
+	/**
140
+	 * Registers a path to be used when searching for documentation files.
141
+	 *
142
+	 * @param $name     A nickname to reference it by later.
143
+	 * @param $path     The server path to the folder.
144
+	 * @return $this
145
+	 */
146
+	public function addDocFolder($name, $path);
147 147
 
148
-    /**
149
-     * Removes a folder from the folders we scan for documentation files
150
-     * within.
151
-     *
152
-     * @param $name
153
-     * @return $this
154
-     */
155
-    public function removeDocFolder($name);
148
+	/**
149
+	 * Removes a folder from the folders we scan for documentation files
150
+	 * within.
151
+	 *
152
+	 * @param $name
153
+	 * @return $this
154
+	 */
155
+	public function removeDocFolder($name);
156 156
 }
Please login to merge, or discard this patch.
myth/Docs/Search.php 1 patch
Indentation   +415 added lines, -415 removed lines patch added patch discarded remove patch
@@ -41,420 +41,420 @@
 block discarded – undo
41 41
 class Search implements DocSearchInterface
42 42
 {
43 43
 
44
-    /**
45
-     * Minimum characters that can be submitted for a search.
46
-     *
47
-     * @var int
48
-     */
49
-    protected $min_chars = 3;
50
-
51
-    /**
52
-     * Maximum characters that can be submitted for a search.
53
-     *
54
-     * @var int
55
-     */
56
-    protected $max_chars = 30;
57
-
58
-    /**
59
-     * Valid file extensions we can search in.
60
-     *
61
-     * @var string
62
-     */
63
-    protected $allowed_file_types = 'html|htm|php|php4|php5|txt|md';
64
-
65
-    /**
66
-     * Which files should we skip over during our search?
67
-     *
68
-     * @var array
69
-     */
70
-    protected $skip_files = ['.', '..', '_404.md', '_toc.ini'];
71
-
72
-    /**
73
-     * How much of each file should we read.
74
-     * Use lower values for faster searches.
75
-     *
76
-     * @var int
77
-     */
78
-    protected $byte_size = 51200;
79
-
80
-    /**
81
-     * Number of words long (approximately)
82
-     * the result excerpt should be.
83
-     *
84
-     * @var int
85
-     */
86
-    protected $excerpt_length = 60;
87
-
88
-    /**
89
-     * The maximum number of results allowed from a single file.
90
-     *
91
-     * @var int
92
-     */
93
-    protected $max_per_file = 1;
94
-
95
-    protected $doc_folders = array();
96
-
97
-    protected $formatters = array();
98
-
99
-    //--------------------------------------------------------------------
100
-
101
-    /**
102
-     * The entry point for performing a search of the documentation.
103
-     *
104
-     * @param null $terms
105
-     * @param array $folders
106
-     *
107
-     * @return array|null
108
-     */
109
-    public function search($terms = null, $folders = [])
110
-    {
111
-        if (empty($terms) || empty($folders)) {
112
-            return null;
113
-        }
114
-
115
-        $results = [];
116
-        $this->doc_folders = $folders;
117
-
118
-        foreach ($folders as $group => $folder) {
119
-            $results = array_merge($results, $this->searchFolder($terms, $folder, $group));
120
-        }
121
-
122
-        return $results;
123
-    }
124
-
125
-    //--------------------------------------------------------------------
126
-
127
-    //--------------------------------------------------------------------
128
-    // Private Methods
129
-    //--------------------------------------------------------------------
130
-
131
-
132
-    /**
133
-     * Searches a single directory worth of files.
134
-     *
135
-     * @param $term
136
-     * @param $folder
137
-     * @param $group_name
138
-     *
139
-     * @return array The results.
140
-     */
141
-    protected function searchFolder($term, $folder, $group_name)
142
-    {
143
-        $results = [];
144
-
145
-        $map = $this->directory_map($folder, 2);
146
-
147
-        $map = $this->flattenMap($map);
148
-
149
-        // Make sure we have something to work with.
150
-        if (! is_array($map) || (is_array($map) && ! count($map))) {
151
-            return [];
152
-        }
153
-
154
-        // Loop over each file and search the contents for our term.
155
-        foreach ($map as $dir => $file) {
156
-            $file_count = 0;
157
-
158
-            if (in_array($file, $this->skip_files)) {
159
-                continue;
160
-            }
161
-
162
-            // Is it a folder?
163
-            if (is_array($file) && count($file)) {
164
-                $results = array_merge($results, $this->searchFolder($term, $folder . '/' . $dir, $group_name));
165
-                continue;
166
-            }
167
-
168
-            // Make sure it's the right file type...
169
-            if (! preg_match("/({$this->allowed_file_types})/i", $file)) {
170
-                continue;
171
-            }
172
-
173
-            $path = is_string($dir) ? $folder . '/' . $dir . '/' . $file : $folder . '/' . $file;
174
-            $term_html = htmlentities($term);
175
-
176
-            // Read in the file text
177
-            $handle = fopen($path, 'r');
178
-            $text = fread($handle, $this->byte_size);
179
-
180
-            // Do we have a match in here somewhere?
181
-            $found = stristr($text, $term) || stristr($text, $term_html);
182
-
183
-            if (! $found) {
184
-                continue;
185
-            }
186
-
187
-            // Escape our terms to safely use in a preg_match
188
-            $excerpt = strip_tags($text);
189
-            $term = preg_quote($term);
190
-            $term = str_replace("/", "\/", "{$term}");
191
-            $term_html = preg_quote($term_html);
192
-            $term_html = str_replace("/", "\/", "{$term_html}");
193
-
194
-            // Add the item to our results with extracts.
195
-            if (preg_match_all(
196
-                "/((\s\S*){0,3})($term|$term_html)((\s?\S*){0,3})/i",
197
-                $excerpt,
198
-                $matches,
199
-                PREG_OFFSET_CAPTURE | PREG_SET_ORDER
200
-            )) {
201
-                foreach ($matches as $match) {
202
-                    if ($file_count >= $this->max_per_file) {
203
-                        continue;
204
-                    }
205
-                    $result_url = '/docs/' . $group_name . '/' . str_replace('.md', '', $file);
206
-
207
-                    foreach ($this->doc_folders as $alias => $folder) {
208
-                        $result_url = str_replace($folder, $alias, $result_url);
209
-                    }
210
-
211
-                    $results[] = [
212
-                        'title' => $this->extractTitle($excerpt, $file),
213
-                        'file' => $folder . '/' . $file,
214
-                        'url' => $result_url,
215
-                        'extract' => $this->buildExtract($excerpt, $term, $match[0][0])
216
-                    ];
217
-
218
-                    $file_count++;
219
-                }
220
-            }
221
-        }
222
-
223
-        return $results;
224
-    }
225
-
226
-    //--------------------------------------------------------------------
227
-
228
-    /**
229
-     * Stores the name of the callback method to run to convert the source
230
-     * files to viewable files. By default, this should be used to register
231
-     * a Mardown Extended formatter with the system, but could be used to
232
-     * extend the
233
-     *
234
-     * @param string $callback_name
235
-     * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
236
-     * @return $this
237
-     */
238
-    public function registerFormatter($callback_name = '', $cascade = false)
239
-    {
240
-        if (empty($callback_name)) return;
241
-
242
-        $this->formatters[] = array($callback_name => $cascade);
243
-
244
-        return $this;
245
-    }
246
-
247
-    //--------------------------------------------------------------------
248
-
249
-    /**
250
-     * Runs the text through the registered formatters.
251
-     *
252
-     * @param $str
253
-     * @return mixed
254
-     */
255
-    public function format($str)
256
-    {
257
-        if (! is_array($this->formatters)) return $str;
258
-
259
-        foreach ($this->formatters as $formatter) {
260
-            $method = key($formatter);
261
-            $cascade = $formatter[$method];
262
-
263
-            $str = call_user_func($method, $str);
264
-
265
-            if (! $cascade) return $str;
266
-        }
267
-
268
-        return $str;
269
-    }
270
-
271
-    //--------------------------------------------------------------------
272
-
273
-
274
-    //--------------------------------------------------------------------
275
-    // Protected Methods
276
-    //--------------------------------------------------------------------
277
-
278
-    /**
279
-     * Converts an array generated by directory_map into a flat array of
280
-     * folders, removing any nested folders and adding them to the path.
281
-     *
282
-     * @param $map
283
-     * @param $prefix   Used to recursively add the folder name...
284
-     * @return mixed
285
-     */
286
-    protected function flattenMap($map, $prefix = '')
287
-    {
288
-        if (! is_array($map) || ! count($map)) {
289
-            return $map;
290
-        }
291
-
292
-        $return = [];
293
-
294
-        foreach ($map as $folder => $files) {
295
-
296
-            // If it's a folder name and an array of files
297
-            // then call this method recursively to flatten it out.
298
-            if (is_array($files)) {
299
-                $return = array_merge($return, $this->flattenMap($files, $prefix . $folder));
300
-                continue;
301
-            }
302
-
303
-            // Else, add our prefix (if any) to the filename...
304
-            $return[] = $prefix . $files;
305
-        }
306
-
307
-        return $return;
308
-    }
309
-
310
-    //--------------------------------------------------------------------
311
-
312
-    /**
313
-     * Handles extracting the text surrounding our match and basic match formatting.
314
-     *
315
-     * @param $excerpt
316
-     * @param $term
317
-     * @param $match_string
318
-     *
319
-     * @return string
320
-     */
321
-    protected function buildExtract($excerpt, $term, $match_string)
322
-    {
323
-        // Find the character positions within the string that our match was found at.
324
-        // That way we'll know from what positions before and after this we want to grab it in.
325
-        $start_offset = stripos($excerpt, $match_string);
326
-
327
-        // Modify the start and end positions based on $this->excerpt_length / 2.
328
-        $buffer = floor($this->excerpt_length / 2);
329
-
330
-        // Adjust our start position
331
-        $start_offset = $start_offset - $buffer;
332
-        if ($start_offset < 0) {
333
-            $start_offset = 0;
334
-        }
335
-
336
-        $extract = substr($excerpt, $start_offset);
337
-
338
-        $extract = strip_tags($this->format($extract));
339
-
340
-        $extract = $this->firstXWords($extract, $this->excerpt_length);
341
-
342
-        // Wrap the search term in a span we can style.
343
-        $extract = str_ireplace($term, '<span class="term-hilight">' . $term . '</span>', $extract);
344
-
345
-        return $extract;
346
-    }
347
-
348
-    //--------------------------------------------------------------------
349
-
350
-    /**
351
-     * Extracts the title from a bit of markdown formatted text. If it doesn't
352
-     * have an h1 or h2, then it uses the filename.
353
-     *
354
-     * @param $excerpt
355
-     * @param $file
356
-     * @return string
357
-     */
358
-    protected function extractTitle($excerpt, $file)
359
-    {
360
-        $title = '';
361
-
362
-        // Easiest to work if this is split into lines.
363
-        $lines = explode("\n", $excerpt);
364
-
365
-        if (is_array($lines) && count($lines)) {
366
-            foreach ($lines as $line) {
367
-                if (strpos($line, '# ') === 0 || strpos($line, '## ') === 0) {
368
-                    $title = trim(str_replace('#', '', $line));
369
-                    break;
370
-                }
371
-            }
372
-        }
373
-
374
-        // If it's empty, we'll use the filename.
375
-        if (empty($title)) {
376
-            $title = str_replace('_', ' ', $file);
377
-            $title = str_replace('.md', ' ', $title);
378
-            $title = ucwords($title);
379
-        }
380
-
381
-        return $title;
382
-    }
383
-    //--------------------------------------------------------------------
384
-
385
-    /**
386
-     * Create a Directory Map
387
-     *
388
-     * Reads the specified directory and builds an array
389
-     * representation of it. Sub-folders contained with the
390
-     * directory will be mapped as well.
391
-     *
392
-     * @param    string $source_dir Path to source
393
-     * @param    int $directory_depth Depth of directories to traverse
394
-     *                        (0 = fully recursive, 1 = current dir, etc)
395
-     * @param    bool $hidden Whether to show hidden files
396
-     * @return    array
397
-     */
398
-    protected function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
399
-    {
400
-        if ($fp = @opendir($source_dir)) {
401
-            $filedata = array();
402
-            $new_depth = $directory_depth - 1;
403
-            $source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
404
-
405
-            while (FALSE !== ($file = readdir($fp))) {
406
-                // Remove '.', '..', and hidden files [optional]
407
-                if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) {
408
-                    continue;
409
-                }
410
-
411
-                is_dir($source_dir . $file) && $file .= DIRECTORY_SEPARATOR;
412
-
413
-                if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file))
414
-                {
415
-                    $filedata[$file] = $this->directory_map($source_dir . $file, $new_depth, $hidden);
416
-                } else
417
-                {
418
-                    // Replace the directory separator here with a forward slash since
419
-                    // Windows uses backward slashes and not all browsers will auto-replace
420
-                    // those slashes in URLs.
421
-                    $filedata[] = str_replace(DIRECTORY_SEPARATOR, '/', $file);
422
-                }
423
-            }
424
-
425
-            closedir($fp);
426
-            return $filedata;
427
-        }
428
-
429
-        return FALSE;
430
-    }
431
-
432
-    //--------------------------------------------------------------------
433
-
434
-    /**
435
-     * Gets the first 'X' words of a string.
436
-     *
437
-     * @param $str
438
-     * @param int $wordCount
439
-     * @return string
440
-     */
441
-    protected function firstXWords($str, $wordCount = 10)
442
-    {
443
-        return implode(
444
-            '',
445
-            array_slice(
446
-                preg_split(
447
-                    '/([\s,\.;\?\!]+)/',
448
-                    $str,
449
-                    $wordCount * 2 + 1,
450
-                    PREG_SPLIT_DELIM_CAPTURE
451
-                ),
452
-                0,
453
-                $wordCount * 2 - 1
454
-            )
455
-        );
456
-    }
457
-
458
-    //--------------------------------------------------------------------
44
+	/**
45
+	 * Minimum characters that can be submitted for a search.
46
+	 *
47
+	 * @var int
48
+	 */
49
+	protected $min_chars = 3;
50
+
51
+	/**
52
+	 * Maximum characters that can be submitted for a search.
53
+	 *
54
+	 * @var int
55
+	 */
56
+	protected $max_chars = 30;
57
+
58
+	/**
59
+	 * Valid file extensions we can search in.
60
+	 *
61
+	 * @var string
62
+	 */
63
+	protected $allowed_file_types = 'html|htm|php|php4|php5|txt|md';
64
+
65
+	/**
66
+	 * Which files should we skip over during our search?
67
+	 *
68
+	 * @var array
69
+	 */
70
+	protected $skip_files = ['.', '..', '_404.md', '_toc.ini'];
71
+
72
+	/**
73
+	 * How much of each file should we read.
74
+	 * Use lower values for faster searches.
75
+	 *
76
+	 * @var int
77
+	 */
78
+	protected $byte_size = 51200;
79
+
80
+	/**
81
+	 * Number of words long (approximately)
82
+	 * the result excerpt should be.
83
+	 *
84
+	 * @var int
85
+	 */
86
+	protected $excerpt_length = 60;
87
+
88
+	/**
89
+	 * The maximum number of results allowed from a single file.
90
+	 *
91
+	 * @var int
92
+	 */
93
+	protected $max_per_file = 1;
94
+
95
+	protected $doc_folders = array();
96
+
97
+	protected $formatters = array();
98
+
99
+	//--------------------------------------------------------------------
100
+
101
+	/**
102
+	 * The entry point for performing a search of the documentation.
103
+	 *
104
+	 * @param null $terms
105
+	 * @param array $folders
106
+	 *
107
+	 * @return array|null
108
+	 */
109
+	public function search($terms = null, $folders = [])
110
+	{
111
+		if (empty($terms) || empty($folders)) {
112
+			return null;
113
+		}
114
+
115
+		$results = [];
116
+		$this->doc_folders = $folders;
117
+
118
+		foreach ($folders as $group => $folder) {
119
+			$results = array_merge($results, $this->searchFolder($terms, $folder, $group));
120
+		}
121
+
122
+		return $results;
123
+	}
124
+
125
+	//--------------------------------------------------------------------
126
+
127
+	//--------------------------------------------------------------------
128
+	// Private Methods
129
+	//--------------------------------------------------------------------
130
+
131
+
132
+	/**
133
+	 * Searches a single directory worth of files.
134
+	 *
135
+	 * @param $term
136
+	 * @param $folder
137
+	 * @param $group_name
138
+	 *
139
+	 * @return array The results.
140
+	 */
141
+	protected function searchFolder($term, $folder, $group_name)
142
+	{
143
+		$results = [];
144
+
145
+		$map = $this->directory_map($folder, 2);
146
+
147
+		$map = $this->flattenMap($map);
148
+
149
+		// Make sure we have something to work with.
150
+		if (! is_array($map) || (is_array($map) && ! count($map))) {
151
+			return [];
152
+		}
153
+
154
+		// Loop over each file and search the contents for our term.
155
+		foreach ($map as $dir => $file) {
156
+			$file_count = 0;
157
+
158
+			if (in_array($file, $this->skip_files)) {
159
+				continue;
160
+			}
161
+
162
+			// Is it a folder?
163
+			if (is_array($file) && count($file)) {
164
+				$results = array_merge($results, $this->searchFolder($term, $folder . '/' . $dir, $group_name));
165
+				continue;
166
+			}
167
+
168
+			// Make sure it's the right file type...
169
+			if (! preg_match("/({$this->allowed_file_types})/i", $file)) {
170
+				continue;
171
+			}
172
+
173
+			$path = is_string($dir) ? $folder . '/' . $dir . '/' . $file : $folder . '/' . $file;
174
+			$term_html = htmlentities($term);
175
+
176
+			// Read in the file text
177
+			$handle = fopen($path, 'r');
178
+			$text = fread($handle, $this->byte_size);
179
+
180
+			// Do we have a match in here somewhere?
181
+			$found = stristr($text, $term) || stristr($text, $term_html);
182
+
183
+			if (! $found) {
184
+				continue;
185
+			}
186
+
187
+			// Escape our terms to safely use in a preg_match
188
+			$excerpt = strip_tags($text);
189
+			$term = preg_quote($term);
190
+			$term = str_replace("/", "\/", "{$term}");
191
+			$term_html = preg_quote($term_html);
192
+			$term_html = str_replace("/", "\/", "{$term_html}");
193
+
194
+			// Add the item to our results with extracts.
195
+			if (preg_match_all(
196
+				"/((\s\S*){0,3})($term|$term_html)((\s?\S*){0,3})/i",
197
+				$excerpt,
198
+				$matches,
199
+				PREG_OFFSET_CAPTURE | PREG_SET_ORDER
200
+			)) {
201
+				foreach ($matches as $match) {
202
+					if ($file_count >= $this->max_per_file) {
203
+						continue;
204
+					}
205
+					$result_url = '/docs/' . $group_name . '/' . str_replace('.md', '', $file);
206
+
207
+					foreach ($this->doc_folders as $alias => $folder) {
208
+						$result_url = str_replace($folder, $alias, $result_url);
209
+					}
210
+
211
+					$results[] = [
212
+						'title' => $this->extractTitle($excerpt, $file),
213
+						'file' => $folder . '/' . $file,
214
+						'url' => $result_url,
215
+						'extract' => $this->buildExtract($excerpt, $term, $match[0][0])
216
+					];
217
+
218
+					$file_count++;
219
+				}
220
+			}
221
+		}
222
+
223
+		return $results;
224
+	}
225
+
226
+	//--------------------------------------------------------------------
227
+
228
+	/**
229
+	 * Stores the name of the callback method to run to convert the source
230
+	 * files to viewable files. By default, this should be used to register
231
+	 * a Mardown Extended formatter with the system, but could be used to
232
+	 * extend the
233
+	 *
234
+	 * @param string $callback_name
235
+	 * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
236
+	 * @return $this
237
+	 */
238
+	public function registerFormatter($callback_name = '', $cascade = false)
239
+	{
240
+		if (empty($callback_name)) return;
241
+
242
+		$this->formatters[] = array($callback_name => $cascade);
243
+
244
+		return $this;
245
+	}
246
+
247
+	//--------------------------------------------------------------------
248
+
249
+	/**
250
+	 * Runs the text through the registered formatters.
251
+	 *
252
+	 * @param $str
253
+	 * @return mixed
254
+	 */
255
+	public function format($str)
256
+	{
257
+		if (! is_array($this->formatters)) return $str;
258
+
259
+		foreach ($this->formatters as $formatter) {
260
+			$method = key($formatter);
261
+			$cascade = $formatter[$method];
262
+
263
+			$str = call_user_func($method, $str);
264
+
265
+			if (! $cascade) return $str;
266
+		}
267
+
268
+		return $str;
269
+	}
270
+
271
+	//--------------------------------------------------------------------
272
+
273
+
274
+	//--------------------------------------------------------------------
275
+	// Protected Methods
276
+	//--------------------------------------------------------------------
277
+
278
+	/**
279
+	 * Converts an array generated by directory_map into a flat array of
280
+	 * folders, removing any nested folders and adding them to the path.
281
+	 *
282
+	 * @param $map
283
+	 * @param $prefix   Used to recursively add the folder name...
284
+	 * @return mixed
285
+	 */
286
+	protected function flattenMap($map, $prefix = '')
287
+	{
288
+		if (! is_array($map) || ! count($map)) {
289
+			return $map;
290
+		}
291
+
292
+		$return = [];
293
+
294
+		foreach ($map as $folder => $files) {
295
+
296
+			// If it's a folder name and an array of files
297
+			// then call this method recursively to flatten it out.
298
+			if (is_array($files)) {
299
+				$return = array_merge($return, $this->flattenMap($files, $prefix . $folder));
300
+				continue;
301
+			}
302
+
303
+			// Else, add our prefix (if any) to the filename...
304
+			$return[] = $prefix . $files;
305
+		}
306
+
307
+		return $return;
308
+	}
309
+
310
+	//--------------------------------------------------------------------
311
+
312
+	/**
313
+	 * Handles extracting the text surrounding our match and basic match formatting.
314
+	 *
315
+	 * @param $excerpt
316
+	 * @param $term
317
+	 * @param $match_string
318
+	 *
319
+	 * @return string
320
+	 */
321
+	protected function buildExtract($excerpt, $term, $match_string)
322
+	{
323
+		// Find the character positions within the string that our match was found at.
324
+		// That way we'll know from what positions before and after this we want to grab it in.
325
+		$start_offset = stripos($excerpt, $match_string);
326
+
327
+		// Modify the start and end positions based on $this->excerpt_length / 2.
328
+		$buffer = floor($this->excerpt_length / 2);
329
+
330
+		// Adjust our start position
331
+		$start_offset = $start_offset - $buffer;
332
+		if ($start_offset < 0) {
333
+			$start_offset = 0;
334
+		}
335
+
336
+		$extract = substr($excerpt, $start_offset);
337
+
338
+		$extract = strip_tags($this->format($extract));
339
+
340
+		$extract = $this->firstXWords($extract, $this->excerpt_length);
341
+
342
+		// Wrap the search term in a span we can style.
343
+		$extract = str_ireplace($term, '<span class="term-hilight">' . $term . '</span>', $extract);
344
+
345
+		return $extract;
346
+	}
347
+
348
+	//--------------------------------------------------------------------
349
+
350
+	/**
351
+	 * Extracts the title from a bit of markdown formatted text. If it doesn't
352
+	 * have an h1 or h2, then it uses the filename.
353
+	 *
354
+	 * @param $excerpt
355
+	 * @param $file
356
+	 * @return string
357
+	 */
358
+	protected function extractTitle($excerpt, $file)
359
+	{
360
+		$title = '';
361
+
362
+		// Easiest to work if this is split into lines.
363
+		$lines = explode("\n", $excerpt);
364
+
365
+		if (is_array($lines) && count($lines)) {
366
+			foreach ($lines as $line) {
367
+				if (strpos($line, '# ') === 0 || strpos($line, '## ') === 0) {
368
+					$title = trim(str_replace('#', '', $line));
369
+					break;
370
+				}
371
+			}
372
+		}
373
+
374
+		// If it's empty, we'll use the filename.
375
+		if (empty($title)) {
376
+			$title = str_replace('_', ' ', $file);
377
+			$title = str_replace('.md', ' ', $title);
378
+			$title = ucwords($title);
379
+		}
380
+
381
+		return $title;
382
+	}
383
+	//--------------------------------------------------------------------
384
+
385
+	/**
386
+	 * Create a Directory Map
387
+	 *
388
+	 * Reads the specified directory and builds an array
389
+	 * representation of it. Sub-folders contained with the
390
+	 * directory will be mapped as well.
391
+	 *
392
+	 * @param    string $source_dir Path to source
393
+	 * @param    int $directory_depth Depth of directories to traverse
394
+	 *                        (0 = fully recursive, 1 = current dir, etc)
395
+	 * @param    bool $hidden Whether to show hidden files
396
+	 * @return    array
397
+	 */
398
+	protected function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
399
+	{
400
+		if ($fp = @opendir($source_dir)) {
401
+			$filedata = array();
402
+			$new_depth = $directory_depth - 1;
403
+			$source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
404
+
405
+			while (FALSE !== ($file = readdir($fp))) {
406
+				// Remove '.', '..', and hidden files [optional]
407
+				if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) {
408
+					continue;
409
+				}
410
+
411
+				is_dir($source_dir . $file) && $file .= DIRECTORY_SEPARATOR;
412
+
413
+				if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file))
414
+				{
415
+					$filedata[$file] = $this->directory_map($source_dir . $file, $new_depth, $hidden);
416
+				} else
417
+				{
418
+					// Replace the directory separator here with a forward slash since
419
+					// Windows uses backward slashes and not all browsers will auto-replace
420
+					// those slashes in URLs.
421
+					$filedata[] = str_replace(DIRECTORY_SEPARATOR, '/', $file);
422
+				}
423
+			}
424
+
425
+			closedir($fp);
426
+			return $filedata;
427
+		}
428
+
429
+		return FALSE;
430
+	}
431
+
432
+	//--------------------------------------------------------------------
433
+
434
+	/**
435
+	 * Gets the first 'X' words of a string.
436
+	 *
437
+	 * @param $str
438
+	 * @param int $wordCount
439
+	 * @return string
440
+	 */
441
+	protected function firstXWords($str, $wordCount = 10)
442
+	{
443
+		return implode(
444
+			'',
445
+			array_slice(
446
+				preg_split(
447
+					'/([\s,\.;\?\!]+)/',
448
+					$str,
449
+					$wordCount * 2 + 1,
450
+					PREG_SPLIT_DELIM_CAPTURE
451
+				),
452
+				0,
453
+				$wordCount * 2 - 1
454
+			)
455
+		);
456
+	}
457
+
458
+	//--------------------------------------------------------------------
459 459
 
460 460
 }
Please login to merge, or discard this patch.
myth/Events/Events.php 1 patch
Indentation   +169 added lines, -169 removed lines patch added patch discarded remove patch
@@ -36,176 +36,176 @@
 block discarded – undo
36 36
 
37 37
 class Events {
38 38
 
39
-    /**
40
-     * The list of listeners.
41
-     *
42
-     * @var array
43
-     */
44
-    protected static $listeners = [];
45
-
46
-    /**
47
-     * Flag to let us know if we've read from the config file
48
-     * and have all of the defined events.
49
-     *
50
-     * @var bool
51
-     */
52
-    protected static $have_read_from_file = false;
53
-
54
-    //--------------------------------------------------------------------
55
-
56
-    /**
57
-     * Registers an action to happen on an event. The action can be any sort
58
-     * of callable:
59
-     *
60
-     *  Events::on('create', 'myFunction');               // procedural function
61
-     *  Events::on('create', ['myClass', 'myMethod']);    // Class::method
62
-     *  Events::on('create', [$myInstance, 'myMethod']);  // Method on an existing instance
63
-     *  Events::on('create', function() {});              // Closure
64
-     *
65
-     * @param $event_name
66
-     * @param callable $callback
67
-     * @param int $priority
68
-     */
69
-    public static function on($event_name, callable $callback, $priority=EVENTS_PRIORITY_NORMAL)
70
-    {
71
-        if (! isset(self::$listeners[$event_name]))
72
-        {
73
-            self::$listeners[$event_name] = [
74
-                true,   // If there's only 1 item, it's sorted.
75
-                [$priority],
76
-                [$callback]
77
-            ];
78
-        }
79
-        else
80
-        {
81
-            self::$listeners[$event_name][0] = false; // Not sorted
82
-            self::$listeners[$event_name][1][] = $priority;
83
-            self::$listeners[$event_name][2][] = $callback;
84
-        }
85
-    }
39
+	/**
40
+	 * The list of listeners.
41
+	 *
42
+	 * @var array
43
+	 */
44
+	protected static $listeners = [];
45
+
46
+	/**
47
+	 * Flag to let us know if we've read from the config file
48
+	 * and have all of the defined events.
49
+	 *
50
+	 * @var bool
51
+	 */
52
+	protected static $have_read_from_file = false;
53
+
54
+	//--------------------------------------------------------------------
55
+
56
+	/**
57
+	 * Registers an action to happen on an event. The action can be any sort
58
+	 * of callable:
59
+	 *
60
+	 *  Events::on('create', 'myFunction');               // procedural function
61
+	 *  Events::on('create', ['myClass', 'myMethod']);    // Class::method
62
+	 *  Events::on('create', [$myInstance, 'myMethod']);  // Method on an existing instance
63
+	 *  Events::on('create', function() {});              // Closure
64
+	 *
65
+	 * @param $event_name
66
+	 * @param callable $callback
67
+	 * @param int $priority
68
+	 */
69
+	public static function on($event_name, callable $callback, $priority=EVENTS_PRIORITY_NORMAL)
70
+	{
71
+		if (! isset(self::$listeners[$event_name]))
72
+		{
73
+			self::$listeners[$event_name] = [
74
+				true,   // If there's only 1 item, it's sorted.
75
+				[$priority],
76
+				[$callback]
77
+			];
78
+		}
79
+		else
80
+		{
81
+			self::$listeners[$event_name][0] = false; // Not sorted
82
+			self::$listeners[$event_name][1][] = $priority;
83
+			self::$listeners[$event_name][2][] = $callback;
84
+		}
85
+	}
86 86
     
87
-    //--------------------------------------------------------------------
88
-
89
-    /**
90
-     * Runs through all subscribed methods running them one at a time,
91
-     * until either:
92
-     *  a) All subscribers have finished or
93
-     *  b) a method returns false, at which point execution of subscribers stops.
94
-     *
95
-     * @param $event_name
96
-     * @return bool
97
-     */
98
-    public static function trigger($event_name, array $arguments = [])
99
-    {
100
-        // Read in our config/events file so that we have them all!
101
-        if (! self::$have_read_from_file)
102
-        {
103
-            if (is_file(APPPATH .'config/events.php'))
104
-            {
105
-                include APPPATH .'config/events.php';
106
-            }
107
-            self::$have_read_from_file = true;
108
-        }
109
-
110
-        foreach (self::listeners($event_name) as $listener)
111
-        {
112
-            $result = call_user_func_array($listener, $arguments);
113
-
114
-            if ($result === false)
115
-            {
116
-                return false;
117
-            }
118
-        }
119
-
120
-        return true;
121
-    }
87
+	//--------------------------------------------------------------------
88
+
89
+	/**
90
+	 * Runs through all subscribed methods running them one at a time,
91
+	 * until either:
92
+	 *  a) All subscribers have finished or
93
+	 *  b) a method returns false, at which point execution of subscribers stops.
94
+	 *
95
+	 * @param $event_name
96
+	 * @return bool
97
+	 */
98
+	public static function trigger($event_name, array $arguments = [])
99
+	{
100
+		// Read in our config/events file so that we have them all!
101
+		if (! self::$have_read_from_file)
102
+		{
103
+			if (is_file(APPPATH .'config/events.php'))
104
+			{
105
+				include APPPATH .'config/events.php';
106
+			}
107
+			self::$have_read_from_file = true;
108
+		}
109
+
110
+		foreach (self::listeners($event_name) as $listener)
111
+		{
112
+			$result = call_user_func_array($listener, $arguments);
113
+
114
+			if ($result === false)
115
+			{
116
+				return false;
117
+			}
118
+		}
119
+
120
+		return true;
121
+	}
122 122
     
123
-    //--------------------------------------------------------------------
124
-
125
-    /**
126
-     * Returns an array of listeners for a single event. They are
127
-     * sorted by priority.
128
-     *
129
-     * If the listener could not be found, returns FALSE, or TRUE if
130
-     * it was removed.
131
-     *
132
-     * @param $event_name
133
-     * @return array
134
-     */
135
-    public static function listeners($event_name)
136
-    {
137
-        if (! isset(self::$listeners[$event_name]))
138
-        {
139
-            return [];
140
-        }
141
-
142
-        // The list is not sorted
143
-        if (! self::$listeners[$event_name][0])
144
-        {
145
-            // Sort it!
146
-            array_multisort(self::$listeners[$event_name][1], SORT_NUMERIC, self::$listeners[$event_name][2]);
147
-
148
-            // Mark it as sorted already!
149
-            self::$listeners[$event_name][0] = true;
150
-        }
151
-
152
-        return self::$listeners[$event_name][2];
153
-    }
154
-
155
-    //--------------------------------------------------------------------
156
-
157
-    /**
158
-     * Removes a single listener from an event.
159
-     *
160
-     * If the listener couldn't be found, returns FALSE, else TRUE if
161
-     * it was removed.
162
-     *
163
-     * @param $event_name
164
-     * @param callable $listener
165
-     * @return bool
166
-     */
167
-    public static function removeListener($event_name, callable $listener)
168
-    {
169
-        if (! isset(self::$listeners[$event_name]))
170
-        {
171
-            return false;
172
-        }
173
-
174
-        foreach (self::$listeners[$event_name][2] as $index => $check)
175
-        {
176
-            if ($check === $listener)
177
-            {
178
-                unset(self::$listeners[$event_name][1][$index]);
179
-                unset(self::$listeners[$event_name][2][$index]);
180
-
181
-                return true;
182
-            }
183
-        }
184
-
185
-        return false;
186
-    }
187
-
188
-    //--------------------------------------------------------------------
189
-
190
-    /**
191
-     * Removes all listeners.
192
-     *
193
-     * If the event_name is specified, only listeners for that event will be
194
-     * removed, otherwise all listeners for all events are removed.
195
-     *
196
-     * @param null $event_name
197
-     */
198
-    public static function removeAllListeners($event_name=null)
199
-    {
200
-        if (! is_null($event_name))
201
-        {
202
-            unset(self::$listeners[$event_name]);
203
-        }
204
-        else {
205
-            self::$listeners = [];
206
-        }
207
-    }
208
-
209
-    //--------------------------------------------------------------------
123
+	//--------------------------------------------------------------------
124
+
125
+	/**
126
+	 * Returns an array of listeners for a single event. They are
127
+	 * sorted by priority.
128
+	 *
129
+	 * If the listener could not be found, returns FALSE, or TRUE if
130
+	 * it was removed.
131
+	 *
132
+	 * @param $event_name
133
+	 * @return array
134
+	 */
135
+	public static function listeners($event_name)
136
+	{
137
+		if (! isset(self::$listeners[$event_name]))
138
+		{
139
+			return [];
140
+		}
141
+
142
+		// The list is not sorted
143
+		if (! self::$listeners[$event_name][0])
144
+		{
145
+			// Sort it!
146
+			array_multisort(self::$listeners[$event_name][1], SORT_NUMERIC, self::$listeners[$event_name][2]);
147
+
148
+			// Mark it as sorted already!
149
+			self::$listeners[$event_name][0] = true;
150
+		}
151
+
152
+		return self::$listeners[$event_name][2];
153
+	}
154
+
155
+	//--------------------------------------------------------------------
156
+
157
+	/**
158
+	 * Removes a single listener from an event.
159
+	 *
160
+	 * If the listener couldn't be found, returns FALSE, else TRUE if
161
+	 * it was removed.
162
+	 *
163
+	 * @param $event_name
164
+	 * @param callable $listener
165
+	 * @return bool
166
+	 */
167
+	public static function removeListener($event_name, callable $listener)
168
+	{
169
+		if (! isset(self::$listeners[$event_name]))
170
+		{
171
+			return false;
172
+		}
173
+
174
+		foreach (self::$listeners[$event_name][2] as $index => $check)
175
+		{
176
+			if ($check === $listener)
177
+			{
178
+				unset(self::$listeners[$event_name][1][$index]);
179
+				unset(self::$listeners[$event_name][2][$index]);
180
+
181
+				return true;
182
+			}
183
+		}
184
+
185
+		return false;
186
+	}
187
+
188
+	//--------------------------------------------------------------------
189
+
190
+	/**
191
+	 * Removes all listeners.
192
+	 *
193
+	 * If the event_name is specified, only listeners for that event will be
194
+	 * removed, otherwise all listeners for all events are removed.
195
+	 *
196
+	 * @param null $event_name
197
+	 */
198
+	public static function removeAllListeners($event_name=null)
199
+	{
200
+		if (! is_null($event_name))
201
+		{
202
+			unset(self::$listeners[$event_name]);
203
+		}
204
+		else {
205
+			self::$listeners = [];
206
+		}
207
+	}
208
+
209
+	//--------------------------------------------------------------------
210 210
 
211 211
 }
Please login to merge, or discard this patch.
myth/Forensics/Console.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -167,11 +167,11 @@
 block discarded – undo
167 167
 
168 168
 	public function reset()
169 169
 	{
170
-	    self::$logs = array(
171
-		    'console'		=> array(),
172
-		    'log_count'		=> 0,
173
-		    'memory_count'	=> 0,
174
-	    );
170
+		self::$logs = array(
171
+			'console'		=> array(),
172
+			'log_count'		=> 0,
173
+			'memory_count'	=> 0,
174
+		);
175 175
 	}
176 176
 
177 177
 	//--------------------------------------------------------------------
Please login to merge, or discard this patch.
myth/Forensics/Profiler.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -531,16 +531,16 @@
 block discarded – undo
531 531
 
532 532
 
533 533
 	public static function get_file_size($size, $retstring = null) {
534
-        // adapted from code at http://aidanlister.com/repos/v/function.size_readable.php
535
-	    $sizes = array('bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
534
+		// adapted from code at http://aidanlister.com/repos/v/function.size_readable.php
535
+		$sizes = array('bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
536 536
 
537
-	    if ($retstring === null) { $retstring = '%01.2f %s'; }
537
+		if ($retstring === null) { $retstring = '%01.2f %s'; }
538 538
 
539 539
 		$lastsizestring = end($sizes);
540 540
 
541 541
 		foreach ($sizes as $sizestring) {
542
-	       	if ($size < 1024) { break; }
543
-	           if ($sizestring != $lastsizestring) { $size /= 1024; }
542
+		   	if ($size < 1024) { break; }
543
+			   if ($sizestring != $lastsizestring) { $size /= 1024; }
544 544
 		}
545 545
 
546 546
 		if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
Please login to merge, or discard this patch.
myth/Forge/FileKit.php 1 patch
Indentation   +197 added lines, -197 removed lines patch added patch discarded remove patch
@@ -32,206 +32,206 @@
 block discarded – undo
32 32
 
33 33
 class FileKit {
34 34
 
35
-    /**
36
-     * Appends data to the end of a file.
37
-     *
38
-     * @param $file
39
-     * @param $content
40
-     * @return bool|int
41
-     */
42
-    public function append($file, $content)
43
-    {
44
-        if (empty($content))
45
-        {
46
-            return true;
47
-        }
48
-
49
-        // Ensure that $content has a newline at the end
50
-        $content = rtrim($content) ."\n";
51
-
52
-        $fh = fopen($file, 'a');
53
-        $result = fwrite($fh, $content);
54
-        fclose($fh);
55
-
56
-        return $result;
57
-    }
58
-
59
-    //--------------------------------------------------------------------
60
-
61
-    /**
62
-     * Prepends string content to a file. For very large files
63
-     * this method could have memory issues, but the primary usage
64
-     * of source files shouldn't ever get large enough to cause issues.
65
-     *
66
-     * @param $file
67
-     * @param $content
68
-     * @return bool|int
69
-     */
70
-    public function prepend($file, $content)
71
-    {
72
-        if (empty($content))
73
-        {
74
-            return true;
75
-        }
76
-
77
-        // Ensure that $content has a newline at the end
78
-        $content = rtrim($content) ."\n";
79
-
80
-        $file_contents = file_get_contents($file);
81
-
82
-        if ($file_contents === false)
83
-        {
84
-            throw new \RuntimeException( sprintf(lang('errors.reading_file'), $file));
85
-        }
86
-
87
-        $result = file_put_contents($file, $content . $file_contents);
88
-
89
-        return (bool)$result;
90
-    }
91
-
92
-    //--------------------------------------------------------------------
93
-
94
-    /**
95
-     * Inserts $content before the line that matches $before. NOT case-
96
-     * sensitive.
97
-     *
98
-     * @param $file
99
-     * @param $before
100
-     * @param $content
101
-     * @return int
102
-     */
103
-    public function before($file, $before, $content)
104
-    {
105
-        if (empty($content))
106
-        {
107
-            return true;
108
-        }
109
-
110
-        // Ensure that $content has a newline at the end
111
-        $content = rtrim($content) ."\n";
112
-
113
-        $lines = file($file);
114
-
115
-        if ($lines === false)
116
-        {
117
-            throw new \RuntimeException( sprintf( lang('errors.file_not_found'), $file ));
118
-        }
119
-
120
-        // Where to insert the row.
121
-        $location = null;
122
-
123
-        foreach ($lines as $index => $line)
124
-        {
125
-            if (strtolower($line) == strtolower($before) )
126
-            {
127
-                $location = $index;
128
-                break;
129
-            }
130
-        }
131
-
132
-        array_splice($lines, $location, 0, $content);
133
-
134
-        $result = file_put_contents($file, $lines);
135
-
136
-        return (bool)$result;
137
-    }
138
-
139
-    //--------------------------------------------------------------------
140
-
141
-    public function after($file, $after, $content)
142
-    {
143
-        if (empty($content))
144
-        {
145
-            return true;
146
-        }
147
-
148
-        // Ensure that $content has a newline at the end
149
-        $content = rtrim($content) ."\n";
150
-
151
-        $lines = file($file);
152
-
153
-        if ($lines === false)
154
-        {
155
-            throw new \RuntimeException( sprintf( lang('errors.file_not_found'), $file ) );
156
-        }
157
-
158
-        // Where to insert the row.
159
-        $location = null;
160
-
161
-        foreach ($lines as $index => $line)
162
-        {
163
-            if (strtolower($line) == strtolower($after) )
164
-            {
165
-                $location = $index;
166
-                break;
167
-            }
168
-        }
169
-
170
-        array_splice($lines, $location +1, 0, $content);
171
-
172
-        $result = file_put_contents($file, $lines);
173
-
174
-        return (bool)$result;
175
-    }
176
-
177
-    //--------------------------------------------------------------------
178
-
179
-    /**
180
-     * Replaces all instances of $search in the file with $replace.
181
-     *
182
-     * @param $file
183
-     * @param $search
184
-     * @param $replace
185
-     * @return int
186
-     */
187
-    public function replaceIn($file, $search, $replace)
188
-    {
189
-        $file_contents = file_get_contents($file);
190
-
191
-        if ($file_contents === false)
192
-        {
193
-            throw new \RuntimeException( sprintf( lang('errors.reading_file'), $file ) );
194
-        }
195
-
196
-        $file_contents = str_replace($search, $replace, $file_contents);
197
-
198
-        $result = file_put_contents($file, $file_contents);
199
-
200
-        return (bool)$result;
201
-    }
202
-
203
-    //--------------------------------------------------------------------
204
-
205
-    /**
206
-     * Uses preg_replace to replace content within the file.
207
-     *
208
-     * @param $file
209
-     * @param $pattern
210
-     * @param $replace
211
-     * @return int
212
-     */
213
-    public function replaceWithRegex($file, $pattern, $replace)
214
-    {
215
-        $file_contents = file_get_contents($file);
216
-
217
-        if ($file_contents === false)
218
-        {
219
-            throw new \RuntimeException( sprintf( lang('errors.reading_file'), $file ) );
220
-        }
35
+	/**
36
+	 * Appends data to the end of a file.
37
+	 *
38
+	 * @param $file
39
+	 * @param $content
40
+	 * @return bool|int
41
+	 */
42
+	public function append($file, $content)
43
+	{
44
+		if (empty($content))
45
+		{
46
+			return true;
47
+		}
48
+
49
+		// Ensure that $content has a newline at the end
50
+		$content = rtrim($content) ."\n";
51
+
52
+		$fh = fopen($file, 'a');
53
+		$result = fwrite($fh, $content);
54
+		fclose($fh);
55
+
56
+		return $result;
57
+	}
58
+
59
+	//--------------------------------------------------------------------
60
+
61
+	/**
62
+	 * Prepends string content to a file. For very large files
63
+	 * this method could have memory issues, but the primary usage
64
+	 * of source files shouldn't ever get large enough to cause issues.
65
+	 *
66
+	 * @param $file
67
+	 * @param $content
68
+	 * @return bool|int
69
+	 */
70
+	public function prepend($file, $content)
71
+	{
72
+		if (empty($content))
73
+		{
74
+			return true;
75
+		}
76
+
77
+		// Ensure that $content has a newline at the end
78
+		$content = rtrim($content) ."\n";
79
+
80
+		$file_contents = file_get_contents($file);
81
+
82
+		if ($file_contents === false)
83
+		{
84
+			throw new \RuntimeException( sprintf(lang('errors.reading_file'), $file));
85
+		}
86
+
87
+		$result = file_put_contents($file, $content . $file_contents);
88
+
89
+		return (bool)$result;
90
+	}
91
+
92
+	//--------------------------------------------------------------------
93
+
94
+	/**
95
+	 * Inserts $content before the line that matches $before. NOT case-
96
+	 * sensitive.
97
+	 *
98
+	 * @param $file
99
+	 * @param $before
100
+	 * @param $content
101
+	 * @return int
102
+	 */
103
+	public function before($file, $before, $content)
104
+	{
105
+		if (empty($content))
106
+		{
107
+			return true;
108
+		}
109
+
110
+		// Ensure that $content has a newline at the end
111
+		$content = rtrim($content) ."\n";
112
+
113
+		$lines = file($file);
114
+
115
+		if ($lines === false)
116
+		{
117
+			throw new \RuntimeException( sprintf( lang('errors.file_not_found'), $file ));
118
+		}
119
+
120
+		// Where to insert the row.
121
+		$location = null;
122
+
123
+		foreach ($lines as $index => $line)
124
+		{
125
+			if (strtolower($line) == strtolower($before) )
126
+			{
127
+				$location = $index;
128
+				break;
129
+			}
130
+		}
131
+
132
+		array_splice($lines, $location, 0, $content);
133
+
134
+		$result = file_put_contents($file, $lines);
135
+
136
+		return (bool)$result;
137
+	}
138
+
139
+	//--------------------------------------------------------------------
140
+
141
+	public function after($file, $after, $content)
142
+	{
143
+		if (empty($content))
144
+		{
145
+			return true;
146
+		}
147
+
148
+		// Ensure that $content has a newline at the end
149
+		$content = rtrim($content) ."\n";
150
+
151
+		$lines = file($file);
152
+
153
+		if ($lines === false)
154
+		{
155
+			throw new \RuntimeException( sprintf( lang('errors.file_not_found'), $file ) );
156
+		}
157
+
158
+		// Where to insert the row.
159
+		$location = null;
160
+
161
+		foreach ($lines as $index => $line)
162
+		{
163
+			if (strtolower($line) == strtolower($after) )
164
+			{
165
+				$location = $index;
166
+				break;
167
+			}
168
+		}
169
+
170
+		array_splice($lines, $location +1, 0, $content);
171
+
172
+		$result = file_put_contents($file, $lines);
173
+
174
+		return (bool)$result;
175
+	}
176
+
177
+	//--------------------------------------------------------------------
178
+
179
+	/**
180
+	 * Replaces all instances of $search in the file with $replace.
181
+	 *
182
+	 * @param $file
183
+	 * @param $search
184
+	 * @param $replace
185
+	 * @return int
186
+	 */
187
+	public function replaceIn($file, $search, $replace)
188
+	{
189
+		$file_contents = file_get_contents($file);
190
+
191
+		if ($file_contents === false)
192
+		{
193
+			throw new \RuntimeException( sprintf( lang('errors.reading_file'), $file ) );
194
+		}
195
+
196
+		$file_contents = str_replace($search, $replace, $file_contents);
197
+
198
+		$result = file_put_contents($file, $file_contents);
199
+
200
+		return (bool)$result;
201
+	}
202
+
203
+	//--------------------------------------------------------------------
204
+
205
+	/**
206
+	 * Uses preg_replace to replace content within the file.
207
+	 *
208
+	 * @param $file
209
+	 * @param $pattern
210
+	 * @param $replace
211
+	 * @return int
212
+	 */
213
+	public function replaceWithRegex($file, $pattern, $replace)
214
+	{
215
+		$file_contents = file_get_contents($file);
216
+
217
+		if ($file_contents === false)
218
+		{
219
+			throw new \RuntimeException( sprintf( lang('errors.reading_file'), $file ) );
220
+		}
221 221
 
222
-        $file_contents = preg_replace($pattern, $replace, $file_contents);
223
-
224
-        $result = false;
222
+		$file_contents = preg_replace($pattern, $replace, $file_contents);
223
+
224
+		$result = false;
225 225
 
226
-        // Don't let us erase a file!
227
-        if (! empty($file_contents))
228
-        {
229
-            $result = file_put_contents( $file, $file_contents );
230
-        }
226
+		// Don't let us erase a file!
227
+		if (! empty($file_contents))
228
+		{
229
+			$result = file_put_contents( $file, $file_contents );
230
+		}
231 231
 
232
-        return (bool)$result;
233
-    }
232
+		return (bool)$result;
233
+	}
234 234
 
235
-    //--------------------------------------------------------------------
235
+	//--------------------------------------------------------------------
236 236
 
237 237
 }
Please login to merge, or discard this patch.
myth/Mail/BaseMailer.php 1 patch
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -40,290 +40,290 @@
 block discarded – undo
40 40
  */
41 41
 class BaseMailer {
42 42
 
43
-    /**
44
-     * How the email is delivered.
45
-     * Either 'send' or 'queue'.
46
-     * @var string
47
-     */
48
-    protected $action = 'send';
49
-
50
-    protected $from     = null;
51
-    protected $to       = null;
52
-    protected $reply_to = null;
53
-    protected $cc       = null;
54
-    protected $bcc      = null;
55
-
56
-    protected $message  = null;
57
-
58
-    protected $theme    = 'email';
59
-    protected $layout   = 'index';
60
-    protected $view     = null;
61
-
62
-    /**
63
-     * The MailService to use. If NULL
64
-     * will use the system default.
65
-     * @var null
66
-     */
67
-    protected $service_name  = null;
68
-
69
-    protected $service = null;
70
-
71
-    /**
72
-     * Used for theming the email messages.
73
-     * @var null
74
-     */
75
-    protected $themer = null;
76
-
77
-    //--------------------------------------------------------------------
78
-
79
-    /**
80
-     * Constructor
81
-     *
82
-     * Simply allows us to override the default settings for this mailer.
83
-     *
84
-     * @param null $options
85
-     */
86
-    public function __construct($options=null)
87
-    {
88
-        if (! empty($options))
89
-        {
90
-            $this->setOptions($options);
91
-        }
92
-    }
93
-
94
-    //--------------------------------------------------------------------
95
-
96
-    /**
97
-     * Sets the basic options available to the mailer, like 'from', 'to',
98
-     * 'cc', 'bcc', etc.
99
-     *
100
-     * @param $options
101
-     */
102
-    public function setOptions($options)
103
-    {
104
-        if (is_array($options))
105
-        {
106
-            foreach ($options as $key => $value)
107
-            {
108
-                if ($key == 'service')
109
-                {
110
-                    $this->service =& $value;
111
-                    continue;
112
-                }
113
-
114
-                if (property_exists($this, $key))
115
-                {
116
-                    $this->$key = $value;
117
-                }
118
-            }
119
-        }
120
-    }
121
-
122
-    //--------------------------------------------------------------------
123
-
124
-
125
-
126
-    /**
127
-     * Sends an email immediately using the system-defined MailService.
128
-     *
129
-     * @param string $to // Who the email is being sent to.
130
-     * @param string $subject // The subject line for the email
131
-     * @param strign $data // the key/value pairs to send to the views.
132
-     * @param string $view // You can override the view used for the email here.
133
-     *                          // You can change themes by prepending theme name
134
-     *                          // like: 'newtheme:newview'
135
-     *
136
-     * @return bool
137
-     */
138
-    public function send($to, $subject, $data=[], $view=null)
139
-    {
140
-        // Are we pretending to send?
141
-        if (config_item('mail.pretend') === true)
142
-        {
143
-            return true;
144
-        }
145
-
146
-        $this->startMailService();
147
-
148
-        $this->service->to($to);
149
-        $this->service->subject($subject);
150
-
151
-        if (is_array($this->from)) {
152
-            $this->service->from($this->from[0], $this->from[1]);
153
-        }
154
-        else
155
-        {
156
-            $this->service->from($this->from);
157
-        }
158
-
159
-        if (! empty($this->cc))         $this->service->cc($this->cc);
160
-        if (! empty($this->bcc))        $this->service->bcc($this->bcc);
161
-
162
-        if (is_array($this->reply_to)) {
163
-            $this->service->reply_to($this->reply_to[0], $this->reply_to[1]);
164
-        }
165
-        else
166
-        {
167
-            $this->service->reply_to($this->reply_to);
168
-        }
169
-
170
-
171
-        // Determine the view to use. We have to hack this a bit with
172
-        // the debug_backtrace, though, to make it all function in the background.
173
-        list(, $method) = debug_backtrace(false);
174
-
175
-        $view = 'emails/'. strtolower( (new \ReflectionClass($this))->getShortName() ) .'/'. $method['function'];
176
-
177
-        // Get our message's text and html versions based on which files exist...
178
-        $basepath = APPPATH .'views/'. $view;
179
-
180
-        // Is a text version available?
181
-        if (file_exists($basepath .'.text.php'))
182
-        {
183
-            $text = $this->load->view($view .'.text.php', $data, true);
184
-            $this->service->text_message($text);
185
-        }
186
-
187
-        // If an html version is around, we need to theme it out
188
-        if (file_exists($basepath .'.html.php'))
189
-        {
190
-            $this->startThemer();
191
-
192
-            $this->themer->setTheme($this->theme);
193
-
194
-            // Determine the correct layout to use
195
-            $layout = ! empty($this->layout) ? $this->layout : NULL;
196
-            $this->themer->setLayout($layout);
197
-
198
-            $this->themer->set($data);
199
-
200
-            // Render the view into a var we can pass to the layout.
201
-            $content = $this->themer->display($view .'.html.php');
202
-
203
-            $this->themer->set('content', $content);
204
-
205
-            $this->service->html_message( $this->themer->display($this->theme .':'. $layout) );
206
-        }
207
-
208
-        if (! $this->service->send() )
209
-        {
210
-            // todo do something here
211
-            return false;
212
-        }
213
-
214
-        return true;
215
-    }
216
-
217
-    //--------------------------------------------------------------------
218
-
219
-    /**
220
-     * Allows you to customize the headers sent with the email. You can
221
-     * do them one at a time by passing $field and $value, or pass an array
222
-     * of $field => $value pairs as the first parameter.
223
-     *
224
-     * @param string|array  $field
225
-     * @param string        $value
226
-     */
227
-    public function header($field, $value=null)
228
-    {
229
-        $this->startMailService();
230
-
231
-        $this->service->setHeader($field, $value);
232
-    }
233
-
234
-    //--------------------------------------------------------------------
235
-
236
-    /**
237
-     * Adds an attachment to the current email that is being built.
238
-     *
239
-     * @param string    $filename
240
-     * @param string    $disposition    like 'inline'. Default is 'attachment'
241
-     * @param string    $newname        If you'd like to rename the file for delivery
242
-     * @param string    $mime           Custom defined mime type.
243
-     */
244
-    public function attach($filename, $disposition=null, $newname=null, $mime=null)
245
-    {
246
-        $this->startMailService();
247
-
248
-        $this->service->attach($filename, $disposition, $newname, $mime);
249
-    }
250
-
251
-    //--------------------------------------------------------------------
252
-
253
-    //--------------------------------------------------------------------
254
-    // Private Methods
255
-    //--------------------------------------------------------------------
256
-
257
-    /**
258
-     * Starts up the service name specified in $service_name.
259
-     *
260
-     * @param $service_name
261
-     */
262
-    protected function startMailService()
263
-    {
264
-        // Only once!
265
-        if (! empty($this->service) && is_object($this->service))
266
-        {
267
-            return;
268
-        }
269
-
270
-        $service_name = ! empty($this->service_name) ? $this->service_name : config_item('mail.default_service');
271
-
272
-        if (! class_exists($service_name))
273
-        {
274
-            throw new \RuntimeException( sprintf( lang('mail.invalid_service'), $service_name) );
275
-        }
276
-
277
-        $this->service = new $service_name();
278
-    }
279
-
280
-    //--------------------------------------------------------------------
281
-
282
-    /**
283
-     * Fires up the default themer so we can use it to theme our HTML messages.
284
-     */
285
-    protected function startThemer()
286
-    {
287
-        /*
43
+	/**
44
+	 * How the email is delivered.
45
+	 * Either 'send' or 'queue'.
46
+	 * @var string
47
+	 */
48
+	protected $action = 'send';
49
+
50
+	protected $from     = null;
51
+	protected $to       = null;
52
+	protected $reply_to = null;
53
+	protected $cc       = null;
54
+	protected $bcc      = null;
55
+
56
+	protected $message  = null;
57
+
58
+	protected $theme    = 'email';
59
+	protected $layout   = 'index';
60
+	protected $view     = null;
61
+
62
+	/**
63
+	 * The MailService to use. If NULL
64
+	 * will use the system default.
65
+	 * @var null
66
+	 */
67
+	protected $service_name  = null;
68
+
69
+	protected $service = null;
70
+
71
+	/**
72
+	 * Used for theming the email messages.
73
+	 * @var null
74
+	 */
75
+	protected $themer = null;
76
+
77
+	//--------------------------------------------------------------------
78
+
79
+	/**
80
+	 * Constructor
81
+	 *
82
+	 * Simply allows us to override the default settings for this mailer.
83
+	 *
84
+	 * @param null $options
85
+	 */
86
+	public function __construct($options=null)
87
+	{
88
+		if (! empty($options))
89
+		{
90
+			$this->setOptions($options);
91
+		}
92
+	}
93
+
94
+	//--------------------------------------------------------------------
95
+
96
+	/**
97
+	 * Sets the basic options available to the mailer, like 'from', 'to',
98
+	 * 'cc', 'bcc', etc.
99
+	 *
100
+	 * @param $options
101
+	 */
102
+	public function setOptions($options)
103
+	{
104
+		if (is_array($options))
105
+		{
106
+			foreach ($options as $key => $value)
107
+			{
108
+				if ($key == 'service')
109
+				{
110
+					$this->service =& $value;
111
+					continue;
112
+				}
113
+
114
+				if (property_exists($this, $key))
115
+				{
116
+					$this->$key = $value;
117
+				}
118
+			}
119
+		}
120
+	}
121
+
122
+	//--------------------------------------------------------------------
123
+
124
+
125
+
126
+	/**
127
+	 * Sends an email immediately using the system-defined MailService.
128
+	 *
129
+	 * @param string $to // Who the email is being sent to.
130
+	 * @param string $subject // The subject line for the email
131
+	 * @param strign $data // the key/value pairs to send to the views.
132
+	 * @param string $view // You can override the view used for the email here.
133
+	 *                          // You can change themes by prepending theme name
134
+	 *                          // like: 'newtheme:newview'
135
+	 *
136
+	 * @return bool
137
+	 */
138
+	public function send($to, $subject, $data=[], $view=null)
139
+	{
140
+		// Are we pretending to send?
141
+		if (config_item('mail.pretend') === true)
142
+		{
143
+			return true;
144
+		}
145
+
146
+		$this->startMailService();
147
+
148
+		$this->service->to($to);
149
+		$this->service->subject($subject);
150
+
151
+		if (is_array($this->from)) {
152
+			$this->service->from($this->from[0], $this->from[1]);
153
+		}
154
+		else
155
+		{
156
+			$this->service->from($this->from);
157
+		}
158
+
159
+		if (! empty($this->cc))         $this->service->cc($this->cc);
160
+		if (! empty($this->bcc))        $this->service->bcc($this->bcc);
161
+
162
+		if (is_array($this->reply_to)) {
163
+			$this->service->reply_to($this->reply_to[0], $this->reply_to[1]);
164
+		}
165
+		else
166
+		{
167
+			$this->service->reply_to($this->reply_to);
168
+		}
169
+
170
+
171
+		// Determine the view to use. We have to hack this a bit with
172
+		// the debug_backtrace, though, to make it all function in the background.
173
+		list(, $method) = debug_backtrace(false);
174
+
175
+		$view = 'emails/'. strtolower( (new \ReflectionClass($this))->getShortName() ) .'/'. $method['function'];
176
+
177
+		// Get our message's text and html versions based on which files exist...
178
+		$basepath = APPPATH .'views/'. $view;
179
+
180
+		// Is a text version available?
181
+		if (file_exists($basepath .'.text.php'))
182
+		{
183
+			$text = $this->load->view($view .'.text.php', $data, true);
184
+			$this->service->text_message($text);
185
+		}
186
+
187
+		// If an html version is around, we need to theme it out
188
+		if (file_exists($basepath .'.html.php'))
189
+		{
190
+			$this->startThemer();
191
+
192
+			$this->themer->setTheme($this->theme);
193
+
194
+			// Determine the correct layout to use
195
+			$layout = ! empty($this->layout) ? $this->layout : NULL;
196
+			$this->themer->setLayout($layout);
197
+
198
+			$this->themer->set($data);
199
+
200
+			// Render the view into a var we can pass to the layout.
201
+			$content = $this->themer->display($view .'.html.php');
202
+
203
+			$this->themer->set('content', $content);
204
+
205
+			$this->service->html_message( $this->themer->display($this->theme .':'. $layout) );
206
+		}
207
+
208
+		if (! $this->service->send() )
209
+		{
210
+			// todo do something here
211
+			return false;
212
+		}
213
+
214
+		return true;
215
+	}
216
+
217
+	//--------------------------------------------------------------------
218
+
219
+	/**
220
+	 * Allows you to customize the headers sent with the email. You can
221
+	 * do them one at a time by passing $field and $value, or pass an array
222
+	 * of $field => $value pairs as the first parameter.
223
+	 *
224
+	 * @param string|array  $field
225
+	 * @param string        $value
226
+	 */
227
+	public function header($field, $value=null)
228
+	{
229
+		$this->startMailService();
230
+
231
+		$this->service->setHeader($field, $value);
232
+	}
233
+
234
+	//--------------------------------------------------------------------
235
+
236
+	/**
237
+	 * Adds an attachment to the current email that is being built.
238
+	 *
239
+	 * @param string    $filename
240
+	 * @param string    $disposition    like 'inline'. Default is 'attachment'
241
+	 * @param string    $newname        If you'd like to rename the file for delivery
242
+	 * @param string    $mime           Custom defined mime type.
243
+	 */
244
+	public function attach($filename, $disposition=null, $newname=null, $mime=null)
245
+	{
246
+		$this->startMailService();
247
+
248
+		$this->service->attach($filename, $disposition, $newname, $mime);
249
+	}
250
+
251
+	//--------------------------------------------------------------------
252
+
253
+	//--------------------------------------------------------------------
254
+	// Private Methods
255
+	//--------------------------------------------------------------------
256
+
257
+	/**
258
+	 * Starts up the service name specified in $service_name.
259
+	 *
260
+	 * @param $service_name
261
+	 */
262
+	protected function startMailService()
263
+	{
264
+		// Only once!
265
+		if (! empty($this->service) && is_object($this->service))
266
+		{
267
+			return;
268
+		}
269
+
270
+		$service_name = ! empty($this->service_name) ? $this->service_name : config_item('mail.default_service');
271
+
272
+		if (! class_exists($service_name))
273
+		{
274
+			throw new \RuntimeException( sprintf( lang('mail.invalid_service'), $service_name) );
275
+		}
276
+
277
+		$this->service = new $service_name();
278
+	}
279
+
280
+	//--------------------------------------------------------------------
281
+
282
+	/**
283
+	 * Fires up the default themer so we can use it to theme our HTML messages.
284
+	 */
285
+	protected function startThemer()
286
+	{
287
+		/*
288 288
          * Setup our Template Engine
289 289
          */
290
-        $themer = config_item('active_themer');
291
-
292
-        if (empty($themer)) {
293
-            throw new \RuntimeException( lang('no_themer') );
294
-        }
295
-
296
-        if (empty($this->themer))
297
-        {
298
-            $this->themer = new $themer( get_instance() );
299
-        }
300
-
301
-        // Register our paths with the themer
302
-        $paths = config_item('theme.paths');
303
-
304
-        foreach ($paths as $key => $path) {
305
-            $this->themer->addThemePath($key, $path);
306
-        }
307
-
308
-        // Set our default theme.
309
-        $this->themer->setDefaultTheme( 'email' );
310
-    }
311
-
312
-    //--------------------------------------------------------------------
313
-
314
-    /**
315
-     * __get magic
316
-     *
317
-     * Allows models to access CI's loaded classes using the same
318
-     * syntax as controllers.
319
-     *
320
-     * @param	string	$key
321
-     */
322
-    public function __get($key)
323
-    {
324
-        return get_instance()->$key;
325
-    }
326
-
327
-    //--------------------------------------------------------------------
290
+		$themer = config_item('active_themer');
291
+
292
+		if (empty($themer)) {
293
+			throw new \RuntimeException( lang('no_themer') );
294
+		}
295
+
296
+		if (empty($this->themer))
297
+		{
298
+			$this->themer = new $themer( get_instance() );
299
+		}
300
+
301
+		// Register our paths with the themer
302
+		$paths = config_item('theme.paths');
303
+
304
+		foreach ($paths as $key => $path) {
305
+			$this->themer->addThemePath($key, $path);
306
+		}
307
+
308
+		// Set our default theme.
309
+		$this->themer->setDefaultTheme( 'email' );
310
+	}
311
+
312
+	//--------------------------------------------------------------------
313
+
314
+	/**
315
+	 * __get magic
316
+	 *
317
+	 * Allows models to access CI's loaded classes using the same
318
+	 * syntax as controllers.
319
+	 *
320
+	 * @param	string	$key
321
+	 */
322
+	public function __get($key)
323
+	{
324
+		return get_instance()->$key;
325
+	}
326
+
327
+	//--------------------------------------------------------------------
328 328
 
329 329
 }
Please login to merge, or discard this patch.