mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-06-28 15:39:42 +02:00
Merge remote-tracking branch 'origin/3.1'
This commit is contained in:
commit
2227ed3629
17
README.md
17
README.md
|
@ -1,6 +1,6 @@
|
|||
## SilverStripe CMS
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-cms.png?branch=3.0)](http://travis-ci.org/silverstripe/silverstripe-cms)
|
||||
[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-cms.png?branch=3.1)](http://travis-ci.org/silverstripe/silverstripe-cms)
|
||||
|
||||
PHP5 Content Management System (CMS), see [http://silverstripe.org](http://silverstripe.org). Requires the [`framework`](http://github.com/silverstripe/sapphire) module and a [`silverstripe-installer`](http://github.com/silverstripe/silverstripe-installer) base project.
|
||||
|
||||
|
@ -9,17 +9,28 @@ PHP5 Content Management System (CMS), see [http://silverstripe.org](http://silve
|
|||
See [installation on different platforms](http://doc.silverstripe.org/framework/en/installation/),
|
||||
and [installation from source](http://doc.silverstripe.org/framework/en/installation/from-source).
|
||||
|
||||
## Bugtracker ##
|
||||
|
||||
Bugs are tracked on [github.com](https://github.com/silverstripe/silverstripe-cms/issues).
|
||||
Please read our [issue reporting guidelines](http://doc.silverstripe.org/framework/en/misc/contributing/issues).
|
||||
|
||||
## Development and Contribution ##
|
||||
|
||||
If you would like to make changes to the SilverStripe core codebase, we have an extensive [guide to contributing code](http://doc.silverstripe.org/framework/en/misc/contributing/code).
|
||||
|
||||
## Links ##
|
||||
|
||||
* [Requirements](http://doc.silverstripe.org/framework/en/installation/server-requirements)
|
||||
* [Changelogs](http://doc.silverstripe.org/framework/en/changelogs/)
|
||||
* [Bugtracker](http://open.silverstripe.org)
|
||||
* [Bugtracker: Framework](https://github.com/silverstripe/sapphire/issues)
|
||||
* [Bugtracker: CMS](https://github.com/silverstripe/silverstripe-cms/issues)
|
||||
* [Bugtracker: Installer](https://github.com/silverstripe/silverstripe-installer/issues)
|
||||
* [Forums](http://silverstripe.org/forums)
|
||||
* [Developer Mailinglist](https://groups.google.com/forum/#!forum/silverstripe-dev)
|
||||
|
||||
## License ##
|
||||
|
||||
Copyright (c) 2007-2012, SilverStripe Limited - www.silverstripe.com
|
||||
Copyright (c) 2007-2013, SilverStripe Limited - www.silverstripe.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This class lets you export a static copy of your site.
|
||||
* It creates a huge number of folders each containing an index.html file.
|
||||
* This preserves the URL naming format.
|
||||
*
|
||||
* Requirements: Unix Filesystem supporting symlinking. Doesn't work on Windows.
|
||||
*
|
||||
* <b>Usage</b>
|
||||
*
|
||||
* The exporter can only be invoked through a URL. Usage on commandline (through [sake](sake)) is not possible at the moment, as we're sending a file to the browser for download.
|
||||
*
|
||||
* <pre>http://localhost/StaticExporter/export</pre>
|
||||
*
|
||||
* Specify a custom baseurl in case you want to deploy the static HTML pages on a different host:
|
||||
* <pre>http://localhost/StaticExporter/export?baseurl=http://example.com</pre>
|
||||
*
|
||||
* @see StaticPublisher
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage export
|
||||
*/
|
||||
class StaticExporter extends Controller {
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'index',
|
||||
'export',
|
||||
);
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
$canAccess = (Director::isDev() || Director::is_cli() || Permission::check("ADMIN"));
|
||||
if(!$canAccess) return Security::permissionFailure($this);
|
||||
}
|
||||
|
||||
|
||||
public function Link($action = null) {
|
||||
return "StaticExporter/$action";
|
||||
}
|
||||
|
||||
public function index() {
|
||||
echo "<h1>"._t('StaticExporter.NAME','Static exporter')."</h1>";
|
||||
echo $this->StaticExportForm()->forTemplate();
|
||||
}
|
||||
|
||||
public function StaticExportForm() {
|
||||
return new Form($this, 'StaticExportForm', new FieldList(
|
||||
// new TextField('folder', _t('StaticExporter.FOLDEREXPORT','Folder to export to')),
|
||||
new TextField('baseurl', _t('StaticExporter.BASEURL','Base URL'))
|
||||
), new FieldList(
|
||||
new FormAction('export', _t('StaticExporter.EXPORTTO','Export to that folder'))
|
||||
));
|
||||
}
|
||||
|
||||
public function export() {
|
||||
// specify custom baseurl for publishing to other webroot
|
||||
if(isset($_REQUEST['baseurl'])) {
|
||||
$base = $_REQUEST['baseurl'];
|
||||
if(substr($base,-1) != '/') $base .= '/';
|
||||
Config::inst()->update('Director', 'alternate_base_url', $base);
|
||||
}
|
||||
|
||||
// setup temporary folders
|
||||
$tmpBaseFolder = TEMP_FOLDER . '/static-export';
|
||||
$tmpFolder = (project()) ? "$tmpBaseFolder/" . project() : "$tmpBaseFolder/site";
|
||||
if(!file_exists($tmpFolder)) Filesystem::makeFolder($tmpFolder);
|
||||
$baseFolderName = basename($tmpFolder);
|
||||
|
||||
// symlink /assets
|
||||
$f1 = ASSETS_PATH;
|
||||
$f2 = Director::baseFolder() . '/' . project();
|
||||
`cd $tmpFolder; ln -s $f1; ln -s $f2`;
|
||||
|
||||
// iterate through all instances of SiteTree
|
||||
$pages = DataObject::get("SiteTree");
|
||||
foreach($pages as $page) {
|
||||
$subfolder = "$tmpFolder/" . trim($page->RelativeLink(null, true), '/');
|
||||
$contentfile = "$tmpFolder/" . trim($page->RelativeLink(null, true), '/') . '/index.html';
|
||||
|
||||
// Make the folder
|
||||
if(!file_exists($subfolder)) {
|
||||
Filesystem::makeFolder($subfolder);
|
||||
}
|
||||
|
||||
// Run the page
|
||||
Requirements::clear();
|
||||
$link = Director::makeRelative($page->Link());
|
||||
$response = Director::test($link);
|
||||
|
||||
// Write to file
|
||||
if($fh = fopen($contentfile, 'w')) {
|
||||
fwrite($fh, $response->getBody());
|
||||
fclose($fh);
|
||||
}
|
||||
}
|
||||
|
||||
// copy homepage (URLSegment: "home") to webroot
|
||||
copy("$tmpFolder/home/index.html", "$tmpFolder/index.html");
|
||||
|
||||
// archive all generated files
|
||||
`cd $tmpBaseFolder; tar -czhf $baseFolderName.tar.gz $baseFolderName`;
|
||||
$archiveContent = file_get_contents("$tmpBaseFolder/$baseFolderName.tar.gz");
|
||||
|
||||
// remove temporary files and folder
|
||||
Filesystem::removeFolder($tmpBaseFolder);
|
||||
|
||||
// return as download to the client
|
||||
$response = SS_HTTPRequest::send_file($archiveContent, "$baseFolderName.tar.gz", 'application/x-tar-gz');
|
||||
echo $response->output();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,7 +43,11 @@ class SiteTreeURLSegmentField extends TextField {
|
|||
}
|
||||
|
||||
public function suggest($request) {
|
||||
if(!$request->getVar('value')) return $this->httpError(405);
|
||||
if(!$request->getVar('value')) {
|
||||
return $this->httpError(405,
|
||||
_t('SiteTreeURLSegmentField.EMPTY', 'Please enter a URL Segment or click cancel')
|
||||
);
|
||||
}
|
||||
$page = $this->getPage();
|
||||
|
||||
// Same logic as SiteTree->onBeforeWrite
|
||||
|
|
|
@ -26,22 +26,34 @@ class ErrorPage extends Page {
|
|||
|
||||
private static $description = 'Custom content for different error cases (e.g. "Page not found")';
|
||||
|
||||
/** @config */
|
||||
/**
|
||||
* @config
|
||||
*/
|
||||
private static $static_filepath = ASSETS_PATH;
|
||||
|
||||
public function canAddChildren($member = null) { return false; }
|
||||
/**
|
||||
* @param $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canAddChildren($member = null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link SS_HTTPResponse} to response to a HTTP error code if an {@link ErrorPage} for that code is present.
|
||||
* Get a {@link SS_HTTPResponse} to response to a HTTP error code if an
|
||||
* {@link ErrorPage} for that code is present.
|
||||
*
|
||||
* @param int $statusCode
|
||||
*
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
static public function response_for($statusCode) {
|
||||
public static function response_for($statusCode) {
|
||||
// first attempt to dynamically generate the error page
|
||||
if($errorPage = DataObject::get_one('ErrorPage', "\"ErrorCode\" = $statusCode")) {
|
||||
Requirements::clear();
|
||||
Requirements::clear_combined_files();
|
||||
|
||||
return ModelAsController::controller_for($errorPage)->handleRequest(new SS_HTTPRequest('GET', ''), DataModel::inst());
|
||||
}
|
||||
|
||||
|
@ -62,10 +74,9 @@ class ErrorPage extends Page {
|
|||
}
|
||||
|
||||
/**
|
||||
* Ensures that there is always a 404 page
|
||||
* by checking if there's an instance of
|
||||
* ErrorPage with a 404 and 500 error code. If there
|
||||
* is not, one is created when the DB is built.
|
||||
* Ensures that there is always a 404 page by checking if there's an
|
||||
* instance of ErrorPage with a 404 and 500 error code. If there is not,
|
||||
* one is created when the DB is built.
|
||||
*/
|
||||
public function requireDefaultRecords() {
|
||||
parent::requireDefaultRecords();
|
||||
|
@ -126,7 +137,7 @@ class ErrorPage extends Page {
|
|||
* Returns an array of arrays, each of which defines
|
||||
* properties for a new ErrorPage record.
|
||||
*
|
||||
* @return Array
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaultRecords() {
|
||||
$data = array(
|
||||
|
@ -153,6 +164,9 @@ class ErrorPage extends Page {
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
|
@ -197,6 +211,7 @@ class ErrorPage extends Page {
|
|||
* When an error page is published, create a static HTML page with its
|
||||
* content, so the page can be shown even when SilverStripe is not
|
||||
* functioning correctly before publishing this page normally.
|
||||
*
|
||||
* @param string|int $fromStage Place to copy from. Can be either a stage name or a version number.
|
||||
* @param string $toStage Place to copy to. Must be a stage name.
|
||||
* @param boolean $createNewVersion Set this to true to create a new version number. By default, the existing version number will be copied over.
|
||||
|
@ -205,10 +220,11 @@ class ErrorPage extends Page {
|
|||
parent::doPublish();
|
||||
|
||||
// Run the page (reset the theme, it might've been disabled by LeftAndMain::init())
|
||||
$oldTheme = Config::inst()->get('SSViewer', 'theme');
|
||||
Config::inst()->update('SSViewer', 'theme', Config::inst()->get('SSViewer', 'custom_theme'));
|
||||
$oldEnabled = Config::inst()->get('SSViewer', 'theme_enabled');
|
||||
Config::inst()->update('SSViewer', 'theme_enabled', true);
|
||||
|
||||
$response = Director::test(Director::makeRelative($this->Link()));
|
||||
Config::inst()->update('SSViewer', 'theme', $oldTheme);
|
||||
Config::inst()->update('SSViewer', 'theme_enabled', $oldEnabled);
|
||||
|
||||
$errorContent = $response->getBody();
|
||||
|
||||
|
@ -239,9 +255,9 @@ class ErrorPage extends Page {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fieldLabels($includerelations = true) {
|
||||
$labels = parent::fieldLabels($includerelations);
|
||||
|
@ -256,12 +272,14 @@ class ErrorPage extends Page {
|
|||
*
|
||||
* @param int $statusCode A HTTP Statuscode, mostly 404 or 500
|
||||
* @param String $locale A locale, e.g. 'de_DE' (Optional)
|
||||
* @return String
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static public function get_filepath_for_errorcode($statusCode, $locale = null) {
|
||||
public static function get_filepath_for_errorcode($statusCode, $locale = null) {
|
||||
if (singleton('ErrorPage')->hasMethod('alternateFilepathForErrorcode')) {
|
||||
return singleton('ErrorPage')-> alternateFilepathForErrorcode($statusCode, $locale);
|
||||
}
|
||||
|
||||
if(class_exists('Translatable') && singleton('SiteTree')->hasExtension('Translatable') && $locale && $locale != Translatable::default_locale()) {
|
||||
return self::config()->static_filepath . "/error-{$statusCode}-{$locale}.html";
|
||||
} else {
|
||||
|
@ -293,9 +311,11 @@ class ErrorPage extends Page {
|
|||
|
||||
/**
|
||||
* Controller for ErrorPages.
|
||||
*
|
||||
* @package cms
|
||||
*/
|
||||
class ErrorPage_Controller extends Page_Controller {
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
|
@ -307,5 +327,3 @@ class ErrorPage_Controller extends Page_Controller {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,371 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Usage: SiteTree::add_extension("FilesystemPublisher('static-folder', 'html')");
|
||||
*
|
||||
* Usage: To work with Subsite module you need to:
|
||||
* - Add FilesystemPublisher::$domain_based_caching = true; in mysite/_config.php
|
||||
* - Added main site host mapping in subsites/host-map.php after everytime a new subsite is created or modified
|
||||
*
|
||||
* You may also have a method $page->pagesAffectedByUnpublishing() to return other URLS
|
||||
* that should be de-cached if $page is unpublished.
|
||||
*
|
||||
* @see http://doc.silverstripe.com/doku.php?id=staticpublisher
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage publishers
|
||||
*/
|
||||
class FilesystemPublisher extends StaticPublisher {
|
||||
|
||||
/**
|
||||
* @var String
|
||||
*/
|
||||
protected $destFolder = 'cache';
|
||||
|
||||
/**
|
||||
* @var String
|
||||
*/
|
||||
protected $fileExtension = 'html';
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var String
|
||||
*/
|
||||
private static $static_base_url = null;
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var Boolean Use domain based cacheing (put cache files into a domain subfolder)
|
||||
* This must be true if you are using this with the "subsites" module.
|
||||
* Please note that this form of caching requires all URLs to be provided absolute
|
||||
* (not relative to the webroot) via {@link SiteTree->AbsoluteLink()}.
|
||||
*/
|
||||
private static $domain_based_caching = false;
|
||||
|
||||
/**
|
||||
* Set a different base URL for the static copy of the site.
|
||||
* This can be useful if you are running the CMS on a different domain from the website.
|
||||
*
|
||||
* @deprecated 3.2 Use the "FilesystemPublisher.static_base_url" config setting instead
|
||||
*/
|
||||
static public function set_static_base_url($url) {
|
||||
Deprecation::notice('3.2', 'Use the "FilesystemPublisher.static_base_url" config setting instead');
|
||||
Config::inst()->update('FilesystemPublisher', 'static_base_url', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $destFolder The folder to save the cached site into.
|
||||
* This needs to be set in framework/static-main.php as well through the {@link $cacheBaseDir} variable.
|
||||
* @param $fileExtension The file extension to use, e.g 'html'.
|
||||
* If omitted, then each page will be placed in its own directory,
|
||||
* with the filename 'index.html'. If you set the extension to PHP, then a simple PHP script will
|
||||
* be generated that can do appropriate cache & redirect header negotation.
|
||||
*/
|
||||
public function __construct($destFolder = 'cache', $fileExtension = null) {
|
||||
// Remove trailing slash from folder
|
||||
if(substr($destFolder, -1) == '/') $destFolder = substr($destFolder, 0, -1);
|
||||
|
||||
$this->destFolder = $destFolder;
|
||||
$this->fileExtension = $fileExtension;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms relative or absolute URLs to their static path equivalent.
|
||||
* This needs to be the same logic that's used to look up these paths through
|
||||
* framework/static-main.php. Does not include the {@link $destFolder} prefix.
|
||||
*
|
||||
* URL filtering will have already taken place for direct SiteTree links via SiteTree->generateURLSegment()).
|
||||
* For all other links (e.g. custom controller actions), we assume that they're pre-sanitized
|
||||
* to suit the filesystem needs, as its impossible to sanitize them without risking to break
|
||||
* the underlying naming assumptions in URL routing (e.g. controller method names).
|
||||
*
|
||||
* Examples (without $domain_based_caching):
|
||||
* - http://mysite.com/mywebroot/ => /index.html (assuming your webroot is in a subfolder)
|
||||
* - http://mysite.com/about-us => /about-us.html
|
||||
* - http://mysite.com/parent/child => /parent/child.html
|
||||
*
|
||||
* Examples (with $domain_based_caching):
|
||||
* - http://mysite.com/mywebroot/ => /mysite.com/index.html (assuming your webroot is in a subfolder)
|
||||
* - http://mysite.com/about-us => /mysite.com/about-us.html
|
||||
* - http://myothersite.com/about-us => /myothersite.com/about-us.html
|
||||
* - http://subdomain.mysite.com/parent/child => /subdomain.mysite.com/parent/child.html
|
||||
*
|
||||
* @param Array $urls Absolute or relative URLs
|
||||
* @return Array Map of original URLs to filesystem paths (relative to {@link $destFolder}).
|
||||
*/
|
||||
public function urlsToPaths($urls) {
|
||||
$mappedUrls = array();
|
||||
foreach($urls as $url) {
|
||||
|
||||
// parse_url() is not multibyte safe, see https://bugs.php.net/bug.php?id=52923.
|
||||
// We assume that the URL hsa been correctly encoded either on storage (for SiteTree->URLSegment),
|
||||
// or through URL collection (for controller method names etc.).
|
||||
$urlParts = @parse_url($url);
|
||||
|
||||
// Remove base folders from the URL if webroot is hosted in a subfolder (same as static-main.php)
|
||||
$path = isset($urlParts['path']) ? $urlParts['path'] : '';
|
||||
if(mb_substr(mb_strtolower($path), 0, mb_strlen(BASE_URL)) == mb_strtolower(BASE_URL)) {
|
||||
$urlSegment = mb_substr($path, mb_strlen(BASE_URL));
|
||||
} else {
|
||||
$urlSegment = $path;
|
||||
}
|
||||
|
||||
// Normalize URLs
|
||||
$urlSegment = trim($urlSegment, '/');
|
||||
|
||||
$filename = $urlSegment ? "$urlSegment.$this->fileExtension" : "index.$this->fileExtension";
|
||||
|
||||
if (Config::inst()->get('FilesystemPublisher', 'domain_based_caching')) {
|
||||
if (!$urlParts) continue; // seriously malformed url here...
|
||||
$filename = $urlParts['host'] . '/' . $filename;
|
||||
}
|
||||
|
||||
$mappedUrls[$url] = ((dirname($filename) == '/') ? '' : (dirname($filename).'/')).basename($filename);
|
||||
}
|
||||
|
||||
return $mappedUrls;
|
||||
}
|
||||
|
||||
public function unpublishPages($urls) {
|
||||
// Do we need to map these?
|
||||
// Detect a numerically indexed arrays
|
||||
if (is_numeric(join('', array_keys($urls)))) $urls = $this->urlsToPaths($urls);
|
||||
|
||||
// This can be quite memory hungry and time-consuming
|
||||
// @todo - Make a more memory efficient publisher
|
||||
increase_time_limit_to();
|
||||
increase_memory_limit_to();
|
||||
|
||||
$cacheBaseDir = $this->getDestDir();
|
||||
|
||||
foreach($urls as $url => $path) {
|
||||
if (file_exists($cacheBaseDir.'/'.$path)) {
|
||||
@unlink($cacheBaseDir.'/'.$path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@link Director::test()} to perform in-memory HTTP requests
|
||||
* on the passed-in URLs.
|
||||
*
|
||||
* @param array $urls Relative URLs
|
||||
* @return array Result, keyed by URL. Keys:
|
||||
* - "statuscode": The HTTP status code
|
||||
* - "redirect": A redirect location (if applicable)
|
||||
* - "path": The filesystem path where the cache has been written
|
||||
*/
|
||||
public function publishPages($urls) {
|
||||
$result = array();
|
||||
|
||||
// Do we need to map these?
|
||||
// Detect a numerically indexed arrays
|
||||
if (is_numeric(join('', array_keys($urls)))) $urls = $this->urlsToPaths($urls);
|
||||
|
||||
// This can be quite memory hungry and time-consuming
|
||||
// @todo - Make a more memory efficient publisher
|
||||
increase_time_limit_to();
|
||||
increase_memory_limit_to();
|
||||
|
||||
// Set the appropriate theme for this publication batch.
|
||||
// This may have been set explicitly via StaticPublisher::static_publisher_theme,
|
||||
// or we can use the last non-null theme.
|
||||
$customTheme = Config::inst()->get('StaticPublisher', 'static_publisher_theme');
|
||||
if(!$customTheme)
|
||||
Config::inst()->update('SSViewer', 'theme', Config::inst()->get('SSViewer', 'custom_theme'));
|
||||
else
|
||||
Config::inst()->update('SSViewer', 'theme', $customTheme);
|
||||
|
||||
$currentBaseURL = Director::baseURL();
|
||||
$staticBaseUrl = Config::inst()->get('FilesystemPublisher', 'static_base_url');
|
||||
if($staticBaseUrl) Config::inst()->update('Director', 'alternate_base_url', $staticBaseUrl);
|
||||
if($this->fileExtension == 'php') {
|
||||
Config::inst()->update('SSViewer', 'rewrite_hash_links', 'php');
|
||||
}
|
||||
if(Config::inst()->get('StaticPublisher', 'echo_progress')) {
|
||||
echo $this->class.": Publishing to " . $staticBaseUrl . "\n";
|
||||
}
|
||||
$files = array();
|
||||
$i = 0;
|
||||
$totalURLs = sizeof($urls);
|
||||
foreach($urls as $url => $path) {
|
||||
$origUrl = $url;
|
||||
$result[$origUrl] = array('statuscode' => null, 'redirect' => null, 'path' => null);
|
||||
|
||||
if($staticBaseUrl) Config::inst()->update('Director', 'alternate_base_url', $staticBaseUrl);
|
||||
$i++;
|
||||
|
||||
if($url && !is_string($url)) {
|
||||
user_error("Bad url:" . var_export($url,true), E_USER_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Config::inst()->get('StaticPublisher', 'echo_progress')) {
|
||||
echo " * Publishing page $i/$totalURLs: $url\n";
|
||||
flush();
|
||||
}
|
||||
|
||||
Requirements::clear();
|
||||
|
||||
if($url == "") $url = "/";
|
||||
if(Director::is_relative_url($url)) $url = Director::absoluteURL($url);
|
||||
$response = Director::test(str_replace('+', ' ', $url));
|
||||
|
||||
if($response) {
|
||||
$result[$origUrl]['statuscode'] = $response->getStatusCode();
|
||||
}
|
||||
|
||||
Requirements::clear();
|
||||
|
||||
singleton('DataObject')->flushCache();
|
||||
|
||||
//skip any responses with a 404 status code. We don't want to turn those into statically cached pages
|
||||
if (!$response || $response->getStatusCode() == '404') continue;
|
||||
|
||||
// Generate file content
|
||||
// PHP file caching will generate a simple script from a template
|
||||
if($this->fileExtension == 'php') {
|
||||
if(is_object($response)) {
|
||||
if($response->getStatusCode() == '301' || $response->getStatusCode() == '302') {
|
||||
$content = $this->generatePHPCacheRedirection($response->getHeader('Location'));
|
||||
} else {
|
||||
$content = $this->generatePHPCacheFile($response->getBody(), HTTP::get_cache_age(), date('Y-m-d H:i:s'));
|
||||
}
|
||||
} else {
|
||||
$content = $this->generatePHPCacheFile($response . '', HTTP::get_cache_age(), date('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
// HTML file caching generally just creates a simple file
|
||||
} else {
|
||||
if(is_object($response)) {
|
||||
if($response->getStatusCode() == '301' || $response->getStatusCode() == '302') {
|
||||
$absoluteURL = Director::absoluteURL($response->getHeader('Location'));
|
||||
$result[$origUrl]['redirect'] = $response->getHeader('Location');
|
||||
$content = "<meta http-equiv=\"refresh\" content=\"2; URL=$absoluteURL\">";
|
||||
} else {
|
||||
$content = $response->getBody();
|
||||
}
|
||||
} else {
|
||||
$content = $response . '';
|
||||
}
|
||||
}
|
||||
|
||||
if(Config::inst()->get('StaticPublisher', 'include_caching_metadata')) {
|
||||
$content = str_replace(
|
||||
'</html>',
|
||||
sprintf("</html>\n\n<!-- %s -->", implode(" ", $this->getMetadata($url))),
|
||||
$content
|
||||
);
|
||||
}
|
||||
|
||||
$files[$origUrl] = array(
|
||||
'Content' => $content,
|
||||
'Folder' => dirname($path).'/',
|
||||
'Filename' => basename($path),
|
||||
);
|
||||
|
||||
// Add externals
|
||||
/*
|
||||
$externals = $this->externalReferencesFor($content);
|
||||
if($externals) foreach($externals as $external) {
|
||||
// Skip absolute URLs
|
||||
if(preg_match('/^[a-zA-Z]+:\/\//', $external)) continue;
|
||||
// Drop querystring parameters
|
||||
$external = strtok($external, '?');
|
||||
|
||||
if(file_exists("../" . $external)) {
|
||||
// Break into folder and filename
|
||||
if(preg_match('/^(.*\/)([^\/]+)$/', $external, $matches)) {
|
||||
$files[$external] = array(
|
||||
"Copy" => "../$external",
|
||||
"Folder" => $matches[1],
|
||||
"Filename" => $matches[2],
|
||||
);
|
||||
|
||||
} else {
|
||||
user_error("Can't parse external: $external", E_USER_WARNING);
|
||||
}
|
||||
} else {
|
||||
$missingFiles[$external] = true;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
if(Config::inst()->get('FilesystemPublisher', 'static_base_url')) Config::inst()->update('Director', 'alternate_base_url', $currentBaseURL);
|
||||
if($this->fileExtension == 'php') {
|
||||
Config::inst()->update('SSViewer', 'rewrite_hash_links', true);
|
||||
}
|
||||
|
||||
$base = BASE_PATH . "/$this->destFolder";
|
||||
foreach($files as $origUrl => $file) {
|
||||
Filesystem::makeFolder("$base/$file[Folder]");
|
||||
|
||||
$path = "$base/$file[Folder]$file[Filename]";
|
||||
$result[$origUrl]['path'] = $path;
|
||||
|
||||
if(isset($file['Content'])) {
|
||||
$fh = fopen($path, "w");
|
||||
fwrite($fh, $file['Content']);
|
||||
fclose($fh);
|
||||
} else if(isset($file['Copy'])) {
|
||||
copy($file['Copy'], $path);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the templated content for a PHP script that can serve up the given piece of content with the given age and expiry
|
||||
*/
|
||||
protected function generatePHPCacheFile($content, $age, $lastModified) {
|
||||
$template = file_get_contents(BASE_PATH . '/cms/code/staticpublisher/CachedPHPPage.tmpl');
|
||||
return str_replace(
|
||||
array('**MAX_AGE**', '**LAST_MODIFIED**', '**CONTENT**'),
|
||||
array((int)$age, $lastModified, $content),
|
||||
$template);
|
||||
}
|
||||
/**
|
||||
* Generate the templated content for a PHP script that can serve up a 301 redirect to the given destionation
|
||||
*/
|
||||
protected function generatePHPCacheRedirection($destination) {
|
||||
$template = file_get_contents(BASE_PATH . '/cms/code/staticpublisher/CachedPHPRedirection.tmpl');
|
||||
return str_replace(
|
||||
array('**DESTINATION**'),
|
||||
array($destination),
|
||||
$template);
|
||||
}
|
||||
|
||||
public function getDestDir() {
|
||||
return BASE_PATH . '/' . $this->destFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all the existing static cache files, as a map of URL => file.
|
||||
* Only returns cache files that will actually map to a URL, based on urlsToPaths.
|
||||
*/
|
||||
public function getExistingStaticCacheFiles() {
|
||||
$cacheDir = BASE_PATH . '/' . $this->destFolder;
|
||||
|
||||
$urlMapper = array_flip($this->urlsToPaths($this->owner->allPagesToCache()));
|
||||
|
||||
$output = array();
|
||||
|
||||
// Glob each dir, then glob each one of those
|
||||
foreach(glob("$cacheDir/*", GLOB_ONLYDIR) as $cacheDir) {
|
||||
foreach(glob($cacheDir.'/*') as $cacheFile) {
|
||||
$mapKey = str_replace(BASE_PATH . "/cache/","",$cacheFile);
|
||||
if(isset($urlMapper[$mapKey])) {
|
||||
$url = $urlMapper[$mapKey];
|
||||
$output[$url] = $cacheFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This static publisher can be used to deploy static content to multiple hosts, by generating the cache files locally and then rsyncing then to
|
||||
* each destination box. This can be used to set up a load-balanced collection of static servers.
|
||||
*
|
||||
* @see http://doc.silverstripe.com/doku.php?id=staticpublisher
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage publishers
|
||||
*/
|
||||
class RsyncMultiHostPublisher extends FilesystemPublisher {
|
||||
/**
|
||||
* @config
|
||||
* Array of rsync targets to publish to. These can either be local file names, or scp-style targets, in the form "user@server:path"
|
||||
*/
|
||||
private static $targets = array();
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $excluded_folders = array();
|
||||
|
||||
/**
|
||||
* Set the targets to publish to.
|
||||
* If target is an scp-style remote path, no password is accepted - we assume key-based authentication to be set up on the application server
|
||||
* initiating the publication.
|
||||
*
|
||||
* @deprecated 3.2 Use the "RsyncMultiHostPublisher.targets" config setting instead
|
||||
* @param $targets An array of targets to publish to. These can either be local file names, or scp-style targets, in the form "user@server:path"
|
||||
*/
|
||||
static public function set_targets($targets) {
|
||||
Deprecation::notice('3.2', 'Use the "RsyncMultiHostPublisher.targets" config setting instead');
|
||||
Config::inst()->update('RsyncMultiHostPublisher', 'targets', $targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify folders to exclude from the rsync
|
||||
* For example, you could exclude assets.
|
||||
*
|
||||
* @deprecated 3.2 Use the "RsyncMultiHostPublisher.excluded_folders" config setting instead
|
||||
*/
|
||||
static public function set_excluded_folders($folders) {
|
||||
Deprecation::notice('3.2', 'Use the "RsyncMultiHostPublisher.excluded_folders" config setting instead');
|
||||
Config::inst()->update('RsyncMultiHostPublisher', 'excluded_folders', $folders);
|
||||
}
|
||||
|
||||
public function publishPages($urls) {
|
||||
parent::publishPages($urls);
|
||||
$base = Director::baseFolder();
|
||||
$framework = FRAMEWORK_DIR;
|
||||
|
||||
// Get variable that can turn off the rsync component of publication
|
||||
if(isset($_GET['norsync']) && $_GET['norsync']) return;
|
||||
|
||||
$extraArg = "";
|
||||
if($this->config()->excluded_folders) foreach($this->config()->excluded_folders as $folder) {
|
||||
$extraArg .= " --exclude " . escapeshellarg($folder);
|
||||
}
|
||||
|
||||
foreach((array)$this->config()->targets as $target) {
|
||||
// Transfer non-PHP content from everything to the target; that will ensure that we have all the JS/CSS/etc
|
||||
$rsyncOutput = `cd $base; rsync -av -e ssh --exclude /.htaccess --exclude /web.config --exclude '*.php' --exclude '*.svn' --exclude '*.git' --exclude '*~' $extraArg --delete . $target`;
|
||||
// Then transfer "safe" PHP from the cache/ directory
|
||||
$rsyncOutput .= `cd $base; rsync -av -e ssh --exclude '*.svn' --exclude '*~' $extraArg --delete cache $target`;
|
||||
// Transfer framework/static-main.php to the target
|
||||
$rsyncOutput .= `cd $base; rsync -av -e ssh --delete $framework/static-main.php $target/$framework`;
|
||||
if(Config::inst()->get('StaticPublisher', 'echo_progress')) echo $rsyncOutput;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage publishers
|
||||
*/
|
||||
abstract class StaticPublisher extends DataExtension {
|
||||
/**
|
||||
* @config
|
||||
* @var boolean Defines whether to output information about publishing or not. By
|
||||
* default, this is off, and should be turned on when you want debugging
|
||||
* (for example, in a cron task)
|
||||
*/
|
||||
private static $echo_progress = false;
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var boolean Realtime static publishing... the second a page
|
||||
* is saved, it is written to the cache
|
||||
*/
|
||||
private static $disable_realtime = false;
|
||||
|
||||
/*
|
||||
* @config
|
||||
* @var boolean This is the current static publishing theme, which can be set at any point
|
||||
* If it's not set, then the last non-null theme, set via Config::inst()->update('SSViewer', 'theme', ) is used
|
||||
* The obvious place to set this is in _config.php
|
||||
*/
|
||||
private static $static_publisher_theme=false;
|
||||
|
||||
abstract public function publishPages($pages);
|
||||
abstract public function unpublishPages($pages);
|
||||
|
||||
/**
|
||||
* @deprecated 3.2 Use the "StaticPublisher.static_publisher_theme" config setting instead
|
||||
* @param [type] $theme [description]
|
||||
*/
|
||||
static public function set_static_publisher_theme($theme){
|
||||
Deprecation::notice('3.2', 'Use the "StaticPublisher.static_publisher_theme" config setting instead');
|
||||
Config::inst()->update('StaticPublisher', 'static_publisher_theme', $theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var boolean Includes a timestamp at the bottom of the generated HTML of each file,
|
||||
* which can be useful for debugging issues with stale caches etc.
|
||||
*/
|
||||
private static $include_caching_metadata = false;
|
||||
|
||||
/**
|
||||
* @deprecated 3.2 Use the "StaticPublisher.static_publisher_theme" config setting instead
|
||||
*/
|
||||
static public function static_publisher_theme(){
|
||||
Deprecation::notice('3.2', 'Use the "StaticPublisher.static_publisher_theme" config setting instead');
|
||||
return Config::inst()->get('StaticPublisher', 'static_publisher_theme');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.2 Use the "StaticPublisher.echo_progress" config setting instead
|
||||
*/
|
||||
static public function echo_progress() {
|
||||
Deprecation::notice('3.2', 'Use the "StaticPublisher.echo_progress" config setting instead');
|
||||
return Config::inst()->get('StaticPublisher', 'echo_progress');
|
||||
}
|
||||
|
||||
/**
|
||||
* Either turns on (boolean true) or off (boolean false) the progress indicators.
|
||||
* @deprecated 3.2 Use the "StaticPublisher.echo_progress" config setting instead
|
||||
* @see StaticPublisher::$echo_progress
|
||||
*/
|
||||
static public function set_echo_progress($progress) {
|
||||
Deprecation::notice('3.2', 'Use the "StaticPublisher.echo_progress" config setting instead');
|
||||
Config::inst()->update('StaticPublisher', 'echo_progress', $progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after a page is published.
|
||||
*/
|
||||
public function onAfterPublish($original) {
|
||||
$this->republish($original);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after link assets have been renamed, and the live site has been updated, without
|
||||
* an actual publish event.
|
||||
*
|
||||
* Only called if the published content exists and has been modified.
|
||||
*/
|
||||
public function onRenameLinkedAsset($original) {
|
||||
$this->republish($original);
|
||||
}
|
||||
|
||||
public function republish($original) {
|
||||
if (Config::inst()->get('StaticPublisher', 'disable_realtime')) return;
|
||||
|
||||
$urls = array();
|
||||
|
||||
if($this->owner->hasMethod('pagesAffectedByChanges')) {
|
||||
$urls = $this->owner->pagesAffectedByChanges($original);
|
||||
} else {
|
||||
$pages = Versioned::get_by_stage('SiteTree', 'Live', '', '', '', 10);
|
||||
if($pages) {
|
||||
foreach($pages as $page) {
|
||||
$urls[] = $page->AbsoluteLink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Similiar to RebuildStaticCacheTask->rebuildCache()
|
||||
foreach($urls as $i => $url) {
|
||||
if(!is_string($url)) {
|
||||
user_error("Bad URL: " . var_export($url, true), E_USER_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove leading slashes from all URLs (apart from the homepage)
|
||||
if(substr($url,-1) == '/' && $url != '/') $url = substr($url,0,-1);
|
||||
|
||||
$urls[$i] = $url;
|
||||
}
|
||||
|
||||
$urls = array_unique($urls);
|
||||
|
||||
$this->publishPages($urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* On after unpublish, get changes and hook into underlying
|
||||
* functionality
|
||||
*/
|
||||
public function onAfterUnpublish($page) {
|
||||
if (Config::inst()->get('StaticPublisher', 'disable_realtime')) return;
|
||||
|
||||
// Get the affected URLs
|
||||
if($this->owner->hasMethod('pagesAffectedByUnpublishing')) {
|
||||
$urls = $this->owner->pagesAffectedByUnpublishing();
|
||||
$urls = array_unique($urls);
|
||||
} else {
|
||||
$urls = array($this->owner->AbsoluteLink());
|
||||
}
|
||||
|
||||
$legalPages = singleton('Page')->allPagesToCache();
|
||||
|
||||
$urlsToRepublish = array_intersect($urls, $legalPages);
|
||||
$urlsToUnpublish = array_diff($urls, $legalPages);
|
||||
|
||||
$this->unpublishPages($urlsToUnpublish);
|
||||
$this->publishPages($urlsToRepublish);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all external references to CSS, JS,
|
||||
*/
|
||||
public function externalReferencesFor($content) {
|
||||
$CLI_content = escapeshellarg($content);
|
||||
$tidy = `echo $CLI_content | tidy -numeric -asxhtml`;
|
||||
$tidy = preg_replace('/xmlns="[^"]+"/','', $tidy);
|
||||
$xContent = new SimpleXMLElement($tidy);
|
||||
//Debug::message($xContent->asXML());
|
||||
|
||||
$xlinks = array(
|
||||
"//link[@rel='stylesheet']/@href" => false,
|
||||
"//script/@src" => false,
|
||||
"//img/@src" => false,
|
||||
"//a/@href" => true,
|
||||
);
|
||||
|
||||
$urls = array();
|
||||
foreach($xlinks as $xlink => $assetsOnly) {
|
||||
$matches = $xContent->xpath($xlink);
|
||||
if($matches) foreach($matches as $item) {
|
||||
$url = $item . '';
|
||||
if($assetsOnly && substr($url,0,7) != ASSETS_DIR . '/') continue;
|
||||
|
||||
$urls[] = $url;
|
||||
}
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides context for this URL, written as an HTML comment to the static file cache,
|
||||
* which can be useful for debugging cache problems. For example, you could track the
|
||||
* event or related page which triggered this republication. The returned data
|
||||
* is unstructured and not intended to be consumed programmatically.
|
||||
* Consider injecting standard HTML <meta> tags instead where applicable.
|
||||
*
|
||||
* Note: Only used when {@link $include_caching_metadata} is enabled.
|
||||
*
|
||||
* @param String
|
||||
* @return Array A numeric array of all metadata.
|
||||
*/
|
||||
function getMetadata($url) {
|
||||
return array(
|
||||
'Cache generated on ' . date('Y-m-d H:i:s T (O)')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,23 +7,20 @@
|
|||
$(".cms-add-form .parent-mode :input").entwine({
|
||||
onclick: function(e) {
|
||||
if(this.val() == 'top') {
|
||||
var parentField = this.closest('form').find('#ParentID .TreeDropdownField');
|
||||
var parentField = this.closest('form').find('#ParentID .TreeDropdownField')
|
||||
parentField.setValue('');
|
||||
parentField.setTitle('');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(".cms-add-form").entwine({
|
||||
onmatch: function() {
|
||||
onadd: function() {
|
||||
var self = this;
|
||||
this.find('#ParentID .TreeDropdownField').bind('change', function() {
|
||||
self.updateTypeList();
|
||||
});
|
||||
this.updateTypeList();
|
||||
this._super();
|
||||
},
|
||||
onunmatch: function() {
|
||||
this._super();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
redraw: function() {
|
||||
var field = this.find(':text'),
|
||||
url = field.data('prefix') + field.val(),
|
||||
url = decodeURI(field.data('prefix') + field.val()),
|
||||
previewUrl = url;
|
||||
|
||||
// Truncate URL if required (ignoring the suffix, retaining the full value)
|
||||
|
@ -33,7 +33,7 @@
|
|||
}
|
||||
|
||||
// Transfer current value to holder
|
||||
this.find('.preview').attr('href', url + field.data('suffix')).text(previewUrl);
|
||||
this.find('.preview').attr('href', encodeURI(url + field.data('suffix'))).text(previewUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -92,12 +92,24 @@
|
|||
* @param (Function)
|
||||
*/
|
||||
suggest: function(val, callback) {
|
||||
var field = this.find(':text'),
|
||||
urlParts = $.path.parseUrl(this.closest('form').attr('action')),
|
||||
var self = this,
|
||||
field = self.find(':text'),
|
||||
urlParts = $.path.parseUrl(self.closest('form').attr('action')),
|
||||
url = urlParts.hrefNoSearch + '/field/' + field.attr('name') + '/suggest/?value=' + encodeURIComponent(val);
|
||||
if(urlParts.search) url += '&' + urlParts.search.replace(/^\?/, '');
|
||||
|
||||
$.get(url, function(data) {callback.apply(this, arguments);});
|
||||
$.ajax({
|
||||
url: url,
|
||||
success: function(data) {
|
||||
callback.apply(this, arguments);
|
||||
},
|
||||
error: function(xhr, status) {
|
||||
xhr.statusText = xhr.responseText;
|
||||
},
|
||||
complete: function() {
|
||||
self.removeClass('loading');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
|
|||
'CMSMAIN.ALERTCLASSNAME': 'Het paginatype wordt aangepast na opslaan van de pagina',
|
||||
'CMSMAIN.URLSEGMENTVALIDATION': 'URLs kunnen alleen bestaan uit letters, cijfers en koppeltekens.',
|
||||
'AssetAdmin.BATCHACTIONSDELETECONFIRM': "Wil je deze mappen %s verwijderen?",
|
||||
'AssetTableField.REALLYDELETE': 'Wil je de geselecteerde bestanden verwijderen??',
|
||||
'AssetTableField.REALLYDELETE': 'Wil je de geselecteerde bestanden verwijderen?',
|
||||
'AssetTableField.MOVING': 'Verplaats %s bestand(en)',
|
||||
'CMSMAIN.AddSearchCriteria': 'Voeg criteria toe',
|
||||
'WidgetAreaEditor.TOOMANY': 'Sorry, je hebt de maximaal aantal widgets bereikt',
|
||||
|
@ -30,6 +30,10 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
|
|||
'Folder.Name': 'Mapnaam',
|
||||
'Tree.AddSubPage': 'Voeg nieuwe pagina toe',
|
||||
'Tree.EditPage': 'Aanpassen',
|
||||
'Tree.Duplicate': 'Dupliceren',
|
||||
'Tree.ThisPageOnly': 'Enkel deze pagina',
|
||||
'Tree.ThisPageAndSubpages': "Deze pagina en subpagina's",
|
||||
'Tree.ShowAsList': 'Toon kinderen als lijst',
|
||||
'CMSMain.ConfirmRestoreFromLive': "Do you really want to copy the published content to the draft site?",
|
||||
'CMSMain.RollbackToVersion': "Do you really want to roll back to version #%s of this page?",
|
||||
'URLSEGMENT.Edit': 'Aanpassen',
|
||||
|
|
|
@ -17,6 +17,23 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
|
|||
'CMSMAIN.PUBLISHING' : 'Publikacja...',
|
||||
'CMSMAIN.RESTORING': 'Odzyskiwanie...',
|
||||
'CMSMAIN.ERRORREVERTING': 'Błąd podczas powrotu do opublikowanej strony',
|
||||
'CMSMAIN.SAVING' : 'Zapisywanie...'
|
||||
'CMSMAIN.SAVING' : 'Zapisywanie...',
|
||||
'CMSMAIN.SELECTMOREPAGES' : "Zaznaczono %s stron.\n\nCzy na pewno chcesz wykonać tę akcje?",
|
||||
'CMSMAIN.ALERTCLASSNAME': 'Ta strona zostanie zaktualizowana po jej zapisani'ur,
|
||||
'CMSMAIN.URLSEGMENTVALIDATION': 'Adres URL może składać się tylko z liter, cyfr i łączników.',
|
||||
'AssetAdmin.BATCHACTIONSDELETECONFIRM': "Czy na pewno usunąć %s folderów?",
|
||||
'AssetTableField.REALLYDELETE': 'Czy na pewno usunąć zaznaczone pliki??',
|
||||
'AssetTableField.MOVING': 'Przenoszenie %s plików',
|
||||
'CMSMAIN.AddSearchCriteria': 'Dodaj kryteria',
|
||||
'WidgetAreaEditor.TOOMANY': 'Przepraszam, ale osiągnięto maksymalną ilość widgetów w tym obszarze',
|
||||
'AssetAdmin.ConfirmDelete': 'Czy na pewno usunąć ten folder i wszystkie pliki w nim zawarte?',
|
||||
'Folder.Name': 'Nazwa folderu',
|
||||
'Tree.AddSubPage': 'Dodaj tutaj nową stronę',
|
||||
'Tree.EditPage': 'Edytuj',
|
||||
'CMSMain.ConfirmRestoreFromLive': "Czy na pewno skopiować opublikowaną treść do strony roboczej?",
|
||||
'CMSMain.RollbackToVersion': "Czy na pewno cofnąć do wersji #%s tej strony?",
|
||||
'URLSEGMENT.Edit': 'Edytuj',
|
||||
'URLSEGMENT.OK': 'OK',
|
||||
'URLSEGMENT.Cancel': 'Anuluj'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -377,10 +377,6 @@ af:
|
|||
many_many_LinkTracking: 'Link Tracking'
|
||||
SiteTreeURLSegmentField:
|
||||
HelpChars: ' Special characters are automatically converted or removed.'
|
||||
StaticExporter:
|
||||
BASEURL: 'Base URL'
|
||||
EXPORTTO: 'Export to that folder'
|
||||
NAME: 'Static exporter'
|
||||
TableListField:
|
||||
SELECT: 'Select:'
|
||||
TableListField.ss:
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
lc_XX:
|
||||
ContentController:
|
||||
DRAFT_SITE_ACCESS_RESTRICTION: "U MUST LOG IN WIF UR CMS PASWORD IN ORDR 2 VIEW TEH DRAFT OR ARCHIVD CONTENT. <a href=\"%s\">CLICK HEAR 2 GO BAK 2 TEH PUBLISHD SIET.</a>"
|
||||
ErrorPage:
|
||||
CODE: "TEH ERRUR CODE"
|
||||
Folder:
|
||||
UNUSEDFILESTITLE: "UNUSD FILEZ"
|
||||
RedirectorPage:
|
||||
HASBEENSETUP: "A REDIRECTOR PAEG HAS BEEN SET UP WITHOUT ANYWHERE 2 REDIRECT 2."
|
||||
HEADER: "DIS PAEG WILL REDIRECT USERS 2 ANOTHR PAEG"
|
||||
OTHERURL: "UDDR WEBSITEZ URL"
|
||||
REDIRECTTO: "REDIRECT 2"
|
||||
REDIRECTTOEXTERNAL: "ANOTHR WEBSIET"
|
||||
REDIRECTTOPAGE: "A PAEG ON UR WEBSEIT"
|
||||
YOURPAGE: "PAEG ON UR WEBSEIT"
|
||||
SiteTree:
|
||||
ACCESSANYONE: "ANY1"
|
||||
ACCESSHEADER: "WAT PEEPS CAN C DAT PAEG ON MY SITE?"
|
||||
ACCESSLOGGEDIN: "LOGGD-IN USERS"
|
||||
ACCESSONLYTHESE: "ONLY THEES PEEPS (CHOOSE FRUM LIST)"
|
||||
ALLOWCOMMENTS: "ALLOW COMMENTZ ON DIS PAEG?"
|
||||
APPEARSVIRTUALPAGES: "DIS CONTENT ALSO APPEARz ON TEH VIRTUAL PAGEZ IN DA %s SECSHUNS."
|
||||
BUTTONCANCELDRAFT: "CANCEL DRAFT CHANGEZ"
|
||||
BUTTONCANCELDRAFTDESC: "DELETE UR DRAFT AN REVERT 2 TEH CURRENTLY PUBLISHD PAEG"
|
||||
BUTTONSAVEPUBLISH: "SAV N PUBLISH"
|
||||
BUTTONUNPUBLISH: "UNPUBLISH"
|
||||
BUTTONUNPUBLISHDESC: "REMOOV DIS PAEG FRUM TEH PUBLISHD SIET"
|
||||
EDITANYONE: "ANYONE HOO CAN LOG-IN 2 TEH CMS"
|
||||
EDITHEADER: "WAT PEEPS CAN EDIT DIS INSIDE TEH CMS?"
|
||||
EDITONLYTHESE: "ONLY THEEZ PEEPS (CHOOSE FRUM LIST)"
|
||||
HASBROKENLINKS: |
|
||||
DIS PAEG HAS BROKD LINKZ.
|
||||
|
||||
HTMLEDITORTITLE: "TEH CONTENT"
|
||||
MENUTITLE: "NAVIGASHUN LABEL"
|
||||
METADESC: "DESCRIPSHUN"
|
||||
METAEXTRA: "CUSTOM META TAGZ"
|
||||
METAKEYWORDS: "KEYWURDZ"
|
||||
METATITLE: "TITLE"
|
||||
PAGETITLE: "NAYM OV TEH PAEG"
|
||||
PAGETYPE: "TYPE OV TEH PAEG"
|
||||
SHOWINMENUS: "SHOU IN MENUZ?"
|
||||
SHOWINSEARCH: "SHOU IN SEARCH?"
|
||||
TABACCESS: "ACCESZ"
|
||||
TABBEHAVIOUR: "BEHAVIOUR"
|
||||
TABCONTENT: "CONTENT"
|
||||
TABMETA: "META-DATA"
|
||||
TOPLEVEL: |
|
||||
SIET CONTENT (TOP LEVEL)
|
||||
|
||||
VirtualPage:
|
||||
CHOOSE: "CHOOSE PAEG 2 LINK 2"
|
||||
EDITCONTENT: "kLICK HEER 2 EDIT TEH CONTENT"
|
||||
HEADER: "DIS R A VIRTUAL PAEG"
|
|
@ -1,126 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage tasks
|
||||
*
|
||||
* @todo Make this use the Task interface once it gets merged back into trunk
|
||||
*/
|
||||
class RebuildStaticCacheTask extends Controller {
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'index',
|
||||
);
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
Versioned::reading_stage('live');
|
||||
|
||||
$canAccess = (Director::isDev() || Director::is_cli() || Permission::check("ADMIN"));
|
||||
if(!$canAccess) return Security::permissionFailure($this);
|
||||
}
|
||||
|
||||
public function index() {
|
||||
Config::inst()->update('StaticPublisher', 'echo_progress', true);
|
||||
|
||||
$page = singleton('Page');
|
||||
if(!$page->hasMethod('allPagesToCache')) {
|
||||
user_error(
|
||||
'RebuildStaticCacheTask::index(): Please define a method "allPagesToCache()" on your Page class to return all pages affected by a cache refresh.',
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if(!empty($_GET['urls'])) $urls = $_GET['urls'];
|
||||
else $urls = $page->allPagesToCache();
|
||||
|
||||
$this->rebuildCache($urls, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the static cache for the pages passed through via $urls
|
||||
*
|
||||
* @param array $urls The URLs of pages to re-fetch and cache.
|
||||
* @param bool $removeAll Remove all stale cache files (default TRUE).
|
||||
*/
|
||||
public function rebuildCache($urls, $removeAll = true) {
|
||||
|
||||
if(!is_array($urls)) {
|
||||
// $urls must be an array
|
||||
user_error("Rebuild cache must be passed an array of urls. Make sure your allPagesToCache function returns an array", E_USER_ERROR);
|
||||
return;
|
||||
};
|
||||
|
||||
if(!Director::is_cli()) echo "<pre>\n";
|
||||
echo "Rebuilding cache.\nNOTE: Please ensure that this page ends with 'Done!' - if not, then something may have gone wrong.\n\n";
|
||||
|
||||
$page = singleton('Page');
|
||||
$cacheBaseDir = $page->getDestDir();
|
||||
|
||||
if(!file_exists($cacheBaseDir)) {
|
||||
Filesystem::makeFolder($cacheBaseDir);
|
||||
}
|
||||
|
||||
if (file_exists($cacheBaseDir.'/lock') && !isset($_REQUEST['force'])) die("There already appears to be a publishing queue running. You can skip warning this by adding ?/&force to the URL.");
|
||||
|
||||
touch($cacheBaseDir.'/lock');
|
||||
|
||||
// Note: Similiar to StaticPublisher->republish()
|
||||
foreach($urls as $i => $url) {
|
||||
if($url && !is_string($url)) {
|
||||
user_error("Bad URL: " . var_export($url, true), E_USER_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove leading slashes from all URLs (apart from the homepage)
|
||||
if(substr($url,-1) == '/' && $url != '/') $url = substr($url,0,-1);
|
||||
|
||||
$urls[$i] = $url;
|
||||
}
|
||||
$urls = array_unique($urls);
|
||||
sort($urls);
|
||||
|
||||
$mappedUrls = $page->urlsToPaths($urls);
|
||||
|
||||
$start = isset($_GET['start']) ? $_GET['start'] : 0;
|
||||
$count = isset($_GET['count']) ? $_GET['count'] : sizeof($urls);
|
||||
if(($start + $count) > sizeof($urls)) $count = sizeof($urls) - $start;
|
||||
|
||||
$mappedUrls = array_slice($mappedUrls, $start, $count);
|
||||
|
||||
if($removeAll && !isset($_GET['urls']) && $start == 0 && file_exists("../cache")) {
|
||||
echo "Removing stale cache files... \n";
|
||||
flush();
|
||||
if (Config::inst()->get('FilesystemPublisher', 'domain_based_caching')) {
|
||||
// Glob each dir, then glob each one of those
|
||||
foreach(glob(BASE_PATH . '/cache/*', GLOB_ONLYDIR) as $cacheDir) {
|
||||
foreach(glob($cacheDir.'/*') as $cacheFile) {
|
||||
$searchCacheFile = trim(str_replace($cacheBaseDir, '', $cacheFile), '\/');
|
||||
if (!in_array($searchCacheFile, $mappedUrls)) {
|
||||
echo " * Deleting $cacheFile\n";
|
||||
@unlink($cacheFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
echo "done.\n\n";
|
||||
}
|
||||
echo "Rebuilding cache from " . sizeof($mappedUrls) . " urls...\n\n";
|
||||
$page->extend('publishPages', $mappedUrls);
|
||||
|
||||
if (file_exists($cacheBaseDir.'/lock')) unlink($cacheBaseDir.'/lock');
|
||||
|
||||
echo "\n\n== Done! ==\n";
|
||||
}
|
||||
|
||||
public function show() {
|
||||
$urls = singleton('Page')->allPagesToCache();
|
||||
echo "<pre>\n";
|
||||
print_r($urls);
|
||||
echo "\n</pre>";
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ Feature: Edit a page
|
|||
When I fill in "Title" with "About Us!"
|
||||
And I fill in the "Content" HTML field with "my new content"
|
||||
And I press the "Save Draft" button
|
||||
Then I should see a "Saved." notice
|
||||
Then I should see a "Saved" button
|
||||
|
||||
When I follow "About Us"
|
||||
Then the "Title" field should contain "About Us!"
|
||||
|
|
|
@ -14,6 +14,7 @@ Feature: Preview a page
|
|||
And I set the CMS mode to "Preview mode"
|
||||
Then I can see the preview panel
|
||||
And the preview contains "About Us"
|
||||
Then I set the CMS mode to "Edit mode"
|
||||
|
||||
# TODO:
|
||||
# - Only tests correctly on fresh database
|
||||
|
|
|
@ -54,7 +54,7 @@ class SiteTreeTest extends SapphireTest {
|
|||
'staff' => 'my-staff',
|
||||
'about' => 'about-us',
|
||||
'staffduplicate' => 'my-staff-2',
|
||||
'product1' => '1.1-test-product',
|
||||
'product1' => '1-1-test-product',
|
||||
'product2' => 'another-product',
|
||||
'product3' => 'another-product-2',
|
||||
'product4' => 'another-product-3',
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Tests for the {@link FilesystemPublisher} class.
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage tests
|
||||
*/
|
||||
class FilesystemPublisherTest extends SapphireTest {
|
||||
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected $orig = array();
|
||||
|
||||
protected static $fixture_file = 'cms/tests/staticpublisher/FilesystemPublisherTest.yml';
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
SiteTree::add_extension("FilesystemPublisher('assets/FilesystemPublisherTest-static-folder/')");
|
||||
|
||||
Config::inst()->update('FilesystemPublisher', 'domain_based_caching', false);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
parent::tearDown();
|
||||
|
||||
SiteTree::remove_extension("FilesystemPublisher('assets/FilesystemPublisherTest-static-folder/')");
|
||||
|
||||
if(file_exists(BASE_PATH . '/assets/FilesystemPublisherTest-static-folder')) {
|
||||
Filesystem::removeFolder(BASE_PATH . '/assets/FilesystemPublisherTest-static-folder');
|
||||
}
|
||||
}
|
||||
|
||||
public function testUrlsToPathsWithRelativeUrls() {
|
||||
$fsp = new FilesystemPublisher('.', 'html');
|
||||
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array('/')),
|
||||
array('/' => './index.html'),
|
||||
'Root URL path mapping'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array('about-us')),
|
||||
array('about-us' => './about-us.html'),
|
||||
'URLsegment path mapping'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array('parent/child')),
|
||||
array('parent/child' => 'parent/child.html'),
|
||||
'Nested URLsegment path mapping'
|
||||
);
|
||||
}
|
||||
|
||||
public function testUrlsToPathsWithAbsoluteUrls() {
|
||||
$fsp = new FilesystemPublisher('.', 'html');
|
||||
|
||||
$url = Director::absoluteBaseUrl();
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => './index.html'),
|
||||
'Root URL path mapping'
|
||||
);
|
||||
|
||||
$url = Director::absoluteBaseUrl() . 'about-us';
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => './about-us.html'),
|
||||
'URLsegment path mapping'
|
||||
);
|
||||
|
||||
$url = Director::absoluteBaseUrl() . 'parent/child';
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => 'parent/child.html'),
|
||||
'Nested URLsegment path mapping'
|
||||
);
|
||||
}
|
||||
|
||||
public function testUrlsToPathsWithDomainBasedCaching() {
|
||||
Config::inst()->update('FilesystemPublisher', 'domain_based_caching', true);
|
||||
|
||||
$fsp = new FilesystemPublisher('.', 'html');
|
||||
|
||||
$url = 'http://domain1.com/';
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => 'domain1.com/index.html'),
|
||||
'Root URL path mapping'
|
||||
);
|
||||
|
||||
$url = 'http://domain1.com/about-us';
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => 'domain1.com/about-us.html'),
|
||||
'URLsegment path mapping'
|
||||
);
|
||||
|
||||
$url = 'http://domain2.com/parent/child';
|
||||
$this->assertEquals(
|
||||
$fsp->urlsToPaths(array($url)),
|
||||
array($url => 'domain2.com/parent/child.html'),
|
||||
'Nested URLsegment path mapping'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple test to ensure that FileSystemPublisher::__construct()
|
||||
* has called parent::__construct() by checking the class property.
|
||||
* The class property is set on {@link Object::__construct()} and
|
||||
* this is therefore a good test to ensure it was called.
|
||||
*
|
||||
* If FilesystemPublisher doesn't call parent::__construct() then
|
||||
* it won't be enabled propery because {@link Object::__construct()}
|
||||
* is where extension instances are set up and subsequently used by
|
||||
* {@link DataObject::defineMethods()}.
|
||||
*/
|
||||
public function testHasCalledParentConstructor() {
|
||||
$fsp = new FilesystemPublisher('.', '.html');
|
||||
$this->assertEquals($fsp->class, 'FilesystemPublisher');
|
||||
}
|
||||
|
||||
/*
|
||||
* These are a few simple tests to check that we will be retrieving the correct theme when we need it
|
||||
* StaticPublishing needs to be able to retrieve a non-null theme at the time publishPages() is called.
|
||||
*/
|
||||
public function testStaticPublisherTheme(){
|
||||
|
||||
//This will be the name of the default theme of this particular project
|
||||
$default_theme= Config::inst()->get('SSViewer', 'theme');
|
||||
|
||||
$p1 = new Page();
|
||||
$p1->URLSegment = strtolower(__CLASS__).'-page-1';
|
||||
$p1->HomepageForDomain = '';
|
||||
$p1->write();
|
||||
$p1->doPublish();
|
||||
|
||||
$current_theme=Config::inst()->get('SSViewer', 'custom_theme');
|
||||
$this->assertEquals($current_theme, $default_theme, 'After a standard publication, the theme is correct');
|
||||
|
||||
//The CMS sometimes sets the theme to null. Check that the $current_custom_theme is still the default
|
||||
Config::inst()->update('SSViewer', 'theme', null);
|
||||
$current_theme=Config::inst()->get('SSViewer', 'custom_theme');
|
||||
$this->assertEquals($current_theme, $default_theme, 'After a setting the theme to null, the default theme is correct');
|
||||
}
|
||||
|
||||
function testPublishPages() {
|
||||
$cacheFolder = '/assets/FilesystemPublisherTest-static-folder/';
|
||||
$cachePath = Director::baseFolder() . $cacheFolder;
|
||||
$publisher = new FilesystemPublisher($cacheFolder, 'html');
|
||||
$page1 = $this->objFromFixture('Page', 'page1');
|
||||
$page1->publish('Stage', 'Live');
|
||||
$redirector1 = $this->objFromFixture('RedirectorPage', 'redirector1');
|
||||
$redirector1->publish('Stage', 'Live');
|
||||
|
||||
$results = $publisher->publishPages(array(
|
||||
$page1->Link(),
|
||||
$redirector1->regularLink(),
|
||||
'/notfound'
|
||||
));
|
||||
|
||||
$this->assertArrayHasKey($page1->Link(), $results);
|
||||
$this->assertEquals(200, $results[$page1->Link()]['statuscode']);
|
||||
$this->assertEquals(
|
||||
realpath($results[$page1->Link()]['path']),
|
||||
realpath($cachePath . './page1.html')
|
||||
);
|
||||
|
||||
$this->assertArrayHasKey($redirector1->regularLink(), $results);
|
||||
$this->assertEquals(301, $results[$redirector1->regularLink()]['statuscode']);
|
||||
$this->assertEquals(Director::baseURL() . 'page1/', $results[$redirector1->regularLink()]['redirect']);
|
||||
$this->assertEquals(
|
||||
realpath($results[$redirector1->regularLink()]['path']),
|
||||
realpath($cachePath . './redirect-to-page1.html')
|
||||
);
|
||||
|
||||
$this->assertArrayHasKey('/notfound', $results);
|
||||
$this->assertEquals(404, $results['/notfound']['statuscode']);
|
||||
$this->assertNull($results['/notfound']['redirect']);
|
||||
$this->assertNull($results['/notfound']['path']);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
Page:
|
||||
page1:
|
||||
URLSegment: page1
|
||||
page1a:
|
||||
URLSegment: page1a
|
||||
Parent: =>Page.page1
|
||||
page2:
|
||||
URLSegment: page2
|
||||
RedirectorPage:
|
||||
redirector1:
|
||||
URLSegment: redirect-to-page1
|
||||
LinkTo: =>Page.page1
|
Loading…
Reference in New Issue
Block a user