Skip to content

Commit

Permalink
Add file collection test, Prepare for SS4 upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
Jake B committed Apr 25, 2018
1 parent a2cbf61 commit 96f534c
Show file tree
Hide file tree
Showing 16 changed files with 389 additions and 131 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/docs export-ignore
/.travis.yml export-ignore
/.scrutinizer.yml export-ignore
/phpcs.xml.dist export-ignore
/phpstan.neon export-ignore
README.md export-ignore
LICENSE.md export-ignore
Expand Down
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ before_script:
- phpenv rehash
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
- if [[ -z $PHPSTAN_TEST ]]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss; fi
- if [[ $PHPSTAN_TEST ]]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require phpstan/phpstan-shim:0.8.4,silbinarywolf/silverstripe-phpstan:dev-master; fi
- if [[ $PHPSTAN_TEST ]]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require phpstan/phpstan-shim:0.9.2; fi
- cd ~/builds/ss

script:
- if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs --standard=PSR2 oldman/src/ oldman/tests/ -n; fi
- if [[ $PHPSTAN_TEST ]]; then vendor/bin/phpstan.phar analyse oldman/src -c "oldman/phpstan.neon" -a "vendor/silbinarywolf/silverstripe-phpstan/bootstrap.php" --level 3; fi
- if [[ $PHPSTAN_TEST ]]; then vendor/bin/phpstan.phar analyse oldman/src -c "oldman/phpstan.neon" -a "oldman/tests/bootstrap-phpstan.php" --level 3; fi
- vendor/bin/phpunit oldman/tests/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ composer require silbinarywolf/silverstripe-oldman:~1.0

## Requirements

* PHP 5.4+
* SilverStripe 3.2+

## Documentation
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
}
],
"require": {
"php": ">=5.4",
"silverstripe/framework": "~3.1",
"silverstripe/cms": "~3.1",
"jamesryanbell/cloudflare": "~1.11"
Expand Down
24 changes: 24 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<ruleset name="SS3">
<description>Coding standard for SilverStripe 4.x</description>

<!-- Don't sniff third party libraries -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/thirdparty/*</exclude-pattern>

<!-- Show progress and output sniff names on violation, and add colours -->
<arg value="sp"/>
<arg name="colors"/>

<!-- Use PSR-2 as a base standard -->
<rule ref="PSR2">
<!-- Allow classes to not declare a namespace -->
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>

<!-- Allow underscores in class names -->
<exclude name="Squiz.Classes.ValidClassName.NotCamelCaps"/>

<!-- Allow non camel cased method names -->
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"/>
</rule>
</ruleset>
16 changes: 14 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
parameters:
earlyTerminatingMethodCalls:
Controller:
- redirect
universalObjectCratesClasses:
- ArrayData
- Config_ForClass
- DataObject
- AbstractQueuedJob # symbiote/silverstripe-queuedjobs module support
excludes_analyse:
- silverstripe-cache
ignoreErrors:
# Temporary until "class_exists" feature is added
# See here: https://github.com/phpstan/phpstan/issues/323
- '%Class Site not found%'
includes:
- ../vendor/silbinarywolf/silverstripe-phpstan/extension.neon
# No SilverStripe support yet
- '%Call to an undefined method SiteTree::Parent()%'
#includes:
# - ../vendor/silbinarywolf/silverstripe-phpstan/extension.neon
191 changes: 115 additions & 76 deletions src/Cloudflare.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,57 @@

namespace Symbiote\Cloudflare;

class Cloudflare extends \Object
use Object;
use Controller;
use Director;
use File;
use Injector;
use SiteTree;
use Site;
use Requirements;
use Cloudflare\Api;
use Cloudflare\Zone\Cache;

class Cloudflare extends Object
{
/**
* Cloudflare can only purge 500 files per request.
*/
const MAX_PURGE_FILES_PER_REQUEST = 500;

/**
* String representation of this class.
* NOTE: Using this as PHP 5.4 does not support `Cloudflare::class`
*
* @var string
*/
const CLOUDFLARE_CLASS = 'Symbiote\Cloudflare\Cloudflare';

/**
* String representation of the "Filesystem" class.
* NOTE: Using this as PHP 5.4 does not support `Filesystem::class`
*
* @var string
*/
const FILESYSTEM_CLASS = 'Symbiote\Cloudflare\Filesystem';

/**
* String representation of a Multisite "Site" DataObject class.
* NOTE: Using this as PHP 5.4 does not support `Site::class`
*
* @var string
*/
const SITE_CLASS = 'Site';

/**
* @var boolean
* @config
*/
private static $enabled = false;

/**
* Email
* eg. silverstripe@gmail.com
*
* @var string
* @config
*/
private static $email = '';

Expand All @@ -27,7 +61,8 @@ class Cloudflare extends \Object
*
* eg. 24ca61e15fb2aa62a31212a90f2674f3451f8
*
* @var string
* @var string
* @config
*/
private static $auth_key = '';

Expand All @@ -36,7 +71,8 @@ class Cloudflare extends \Object
*
* eg. 73a40b2c0c10f468cb658f67b9d46fff
*
* @var string
* @var string
* @config
*/
private static $zone_id = '';

Expand All @@ -48,31 +84,15 @@ class Cloudflare extends \Object
*
* TODO(Jake): Perhaps change this to a array/list for Multisite support?
*
* @var string
* @config
* @var string
*/
private static $base_url = '';

/**
* TODO(Jake): Not implemented yet as not necessary.
*
* The directories to scan recursively for CSS/JS. If empty array, defaults to:
* - array('%BASE_FOLDER%')
*
* It's recommended that if you only use CSS/JS/Images from your theme folder that you
* configure this in YML to:
* - '%BASE_FOLDER%/themes'
*
* @config
* @var string
*/
//private static $scan_directories = array();

/**
* Files with these extensions to purge when clearing images.
* The other file extensions are read from File::app_categories['image'].
*
* @config
* @var array
*/
private static $image_file_extensions = array(
Expand All @@ -93,38 +113,22 @@ class Cloudflare extends \Object
public function __construct()
{
parent::__construct();
$this->filesystem = Injector::inst()->get(self::FILESYSTEM_CLASS);
if ($this->config()->enabled) {
$this->client = new \Cloudflare\Api($this->config()->email, $this->config()->auth_key);
$this->filesystem = \Injector::inst()->get('Symbiote\Cloudflare\Filesystem');
$this->client = new Api($this->config()->email, $this->config()->auth_key);
}
}

/**
* @return CloudflareResult|null
*/
public function purgePage(\SiteTree $page)
public function purgePage(SiteTree $page)
{
if (!$this->client) {
return null;
}
$files = array();

// Use alternate base url if defined for cache clearing
$baseURL = $this->config()->base_url;
$pageLink = '';
if ($baseURL) {
$pageLink = \Controller::join_links($baseURL, $page->Link());
} else {
$pageLink = $page->AbsoluteLink();
}
$files[] = $pageLink;

// If /home/ for HomePage, also add "/" to be cleared.
if ($this->isHomePage($page)) {
$files[] = substr($pageLink, 0, (strrpos($pageLink, '/home')));
}

$cache = new \Cloudflare\Zone\Cache($this->client);
$files = $this->getLinksToPurgeByPage($page);
$cache = new Cache($this->client);
$response = $cache->purge_files($this->getZoneIdentifier(), $files);
$result = new CloudflareResult($files, $response->errors);
return $result;
Expand All @@ -138,7 +142,7 @@ public function purgeAll()
if (!$this->client) {
return null;
}
$cache = new \Cloudflare\Zone\Cache($this->client);
$cache = new Cache($this->client);
$response = $cache->purge($this->getZoneIdentifier(), true);

$result = new CloudflareResult(array(), $response->errors);
Expand All @@ -150,7 +154,7 @@ public function purgeAll()
*/
public function purgeImages()
{
$appCategories = \File::config()->app_categories;
$appCategories = File::config()->app_categories;
if (!isset($appCategories['image'])) {
user_error('Missing "image" category on File::app_categories.', E_USER_WARNING);
return null;
Expand Down Expand Up @@ -188,7 +192,7 @@ public function purgeURLs(array $absoluteOrRelativeURLList)
// Get base URL (for conversion of relative URL to absolute URL)
$baseURL = $this->config()->base_url;
if (!$baseURL) {
$baseURL = \Director::absoluteBaseURL();
$baseURL = Director::absoluteBaseURL();
}

// Process list of relative/absolute URLs
Expand All @@ -199,13 +203,13 @@ public function purgeURLs(array $absoluteOrRelativeURLList)

// Convert to absolute URL
if (!$isAbsoluteURL) {
$urlsToPurge[] = \Controller::join_links($baseURL, $absoluteOrRelativeURL);
$urlsToPurge[] = Controller::join_links($baseURL, $absoluteOrRelativeURL);
continue;
}
$urlsToPurge[] = $absoluteOrRelativeURL;
}

$cache = new \Cloudflare\Zone\Cache($this->client);
$cache = new Cache($this->client);
$response = $cache->purge_files($this->getZoneIdentifier(), $urlsToPurge);

$result = new CloudflareResult($urlsToPurge, $response->errors);
Expand All @@ -228,32 +232,11 @@ protected function purgeFilesByExtensions(array $fileExtensions)
if (!$this->client) {
return null;
}
$cache = new \Cloudflare\Zone\Cache($this->client);
$zoneIdentifier = $this->getZoneIdentifier();

// Scan files in the project directory to purge
$folderList = array(
// Get all files built by `Requirements` system (*.css, *.js)
\Director::baseFolder().'/'.\Requirements::backend()->getCombinedFilesFolder(),
// Get all module / theme files
\Director::baseFolder()
);
$files = array();
foreach ($folderList as $folder) {
$files = array_merge($files, $this->filesystem->getFilesWithExtensionsRecursively($folder, $fileExtensions));
}

// Get all files in database and purge (not using local scan for /assets/ so we can support remotely hosted files in S3/etc)
$fileExtensionsPrefixedWithDot = array();
foreach ($fileExtensions as $fileExtension) {
$fileExtensionsPrefixedWithDot[] = '.'.$fileExtension;
}
$fileRecordList = \File::get()->filter(array(
'Filename:EndsWith' => $fileExtensionsPrefixedWithDot
));
$files = array_merge($files, $fileRecordList->map('ID', 'Link')->toArray());
$files = $this->getFilesToPurgeByExtensions($fileExtensions, false);

// Purge files
$cache = new Cache($this->client);
$zoneIdentifier = $this->getZoneIdentifier();
$errors = array();
foreach (array_chunk($files, self::MAX_PURGE_FILES_PER_REQUEST) as $filesChunk) {
$response = $cache->purge_files($zoneIdentifier, $filesChunk);
Expand All @@ -269,13 +252,69 @@ protected function purgeFilesByExtensions(array $fileExtensions)

/**
* Check if page is the home page.
* Supports Multisites. (ie. \Site record exists at top of tree)
* Supports Multisites. (ie. "Site" record exists at top of tree)
*
* @return boolean
*/
protected function isHomePage(\SiteTree $page)
protected function isHomePage(SiteTree $page)
{
$parent = $page->Parent();
return $page->URLSegment === 'home' && ((class_exists('Site') && $parent instanceof \Site) || !$parent->exists());
return $page->URLSegment === 'home' && ((class_exists(self::SITE_CLASS) && $parent instanceof Site) || !$parent->exists());
}

/**
* @return array
*/
private function getLinksToPurgeByPage(SiteTree $page)
{
$files = array();
// Use alternate base url if defined for cache clearing
$baseURL = $this->config()->base_url;
$pageLink = '';
if ($baseURL) {
$pageLink = Controller::join_links($baseURL, $page->Link());
} else {
$pageLink = $page->AbsoluteLink();
}
$files[] = $pageLink;

// If /home/ for HomePage, also add "/" to be cleared.
if ($this->isHomePage($page)) {
$files[] = substr($pageLink, 0, (strrpos($pageLink, '/home')));
}
return $files;
}

/**
* @return array
*/
private function getFilesToPurgeByExtensions(array $fileExtensions, $ignoreDatabaseRecords)
{
// Scan files in the project directory to purge
$folderList = array(
// Get all files built by `Requirements` system (*.css, *.js)
Director::baseFolder().'/'.Requirements::backend()->getCombinedFilesFolder(),
// Get all module / theme files
Director::baseFolder()
);
$files = array();
foreach ($folderList as $folder) {
$files = array_merge($files, $this->filesystem->getFilesWithExtensionsRecursively($folder, $fileExtensions));
}

// Get all files in database and purge (not using local scan for /assets/ so we can support remotely hosted files in S3/etc)
if (!$ignoreDatabaseRecords) {
$fileExtensionsPrefixedWithDot = array();
foreach ($fileExtensions as $fileExtension) {
$fileExtensionsPrefixedWithDot[] = '.'.$fileExtension;
}
$fileRecordList = File::get()->filter(
array(
'Filename:EndsWith' => $fileExtensionsPrefixedWithDot
)
);
$files = array_merge($files, $fileRecordList->map('ID', 'Link')->toArray());
}
return $files;
}
}
Loading

0 comments on commit 96f534c

Please sign in to comment.