mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #1022 from simonwelsh/indent-sniff_master
Add codesniffer that ensures indentation is with tabs.
This commit is contained in:
commit
0b7ac904c7
@ -22,7 +22,8 @@ before_script:
|
||||
|
||||
script:
|
||||
- phpunit -c phpunit.xml.dist
|
||||
- phpcs --encoding=utf-8 --tab-width=4 --standard=framework/tests/phpcs -np framework
|
||||
- phpcs --encoding=utf-8 --tab-width=4 --standard=framework/tests/phpcs/ruleset.xml -np framework
|
||||
- phpcs --encoding=utf-8 --standard=framework/tests/phpcs/tabs.xml -np framework
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
@ -26,15 +26,15 @@ class CMSProfileController extends LeftAndMain {
|
||||
$form->Fields()->push(new HiddenField('ID', null, Member::currentUserID()));
|
||||
$form->Actions()->push(
|
||||
FormAction::create('save',_t('CMSMain.SAVE', 'Save'))
|
||||
->addExtraClass('ss-ui-button ss-ui-action-constructive')
|
||||
->setAttribute('data-icon', 'accept')
|
||||
->setUseButtonTag(true)
|
||||
);
|
||||
$form->Actions()->removeByName('delete');
|
||||
$form->setValidator(new Member_Validator());
|
||||
$form->setTemplate('Form');
|
||||
$form->setAttribute('data-pjax-fragment', null);
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
->addExtraClass('ss-ui-button ss-ui-action-constructive')
|
||||
->setAttribute('data-icon', 'accept')
|
||||
->setUseButtonTag(true)
|
||||
);
|
||||
$form->Actions()->removeByName('delete');
|
||||
$form->setValidator(new Member_Validator());
|
||||
$form->setTemplate('Form');
|
||||
$form->setAttribute('data-pjax-fragment', null);
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
$form->addExtraClass('member-profile-form root-form cms-edit-form cms-panel-padded center');
|
||||
|
||||
return $form;
|
||||
|
@ -296,7 +296,7 @@ abstract class ModelAdmin extends LeftAndMain {
|
||||
*
|
||||
* @return array Map of model class names to importer instances
|
||||
*/
|
||||
public function getModelImporters() {
|
||||
public function getModelImporters() {
|
||||
$importerClasses = $this->stat('model_importers');
|
||||
|
||||
// fallback to all defined models if not explicitly defined
|
||||
|
@ -153,8 +153,8 @@
|
||||
"select_limit" : 1,
|
||||
'initially_select': [this.find('.current').attr('id')]
|
||||
},
|
||||
"crrm": {
|
||||
'move': {
|
||||
"crrm": {
|
||||
'move': {
|
||||
// Check if a node is allowed to be moved.
|
||||
// Caution: Runs on every drag over a new node
|
||||
'check_move': function(data) {
|
||||
|
@ -301,7 +301,7 @@ jQuery.noConflict();
|
||||
*/
|
||||
submitForm: function(form, button, callback, ajaxOptions) {
|
||||
var self = this;
|
||||
|
||||
|
||||
// look for save button
|
||||
if(!button) button = this.find('.Actions :submit[name=action_save]');
|
||||
// default to first button if none given - simulates browser behaviour
|
||||
|
@ -170,8 +170,8 @@
|
||||
convertUrlToDataUrl: function( absUrl ) {
|
||||
var u = path.parseUrl( absUrl );
|
||||
if ( path.isEmbeddedPage( u ) ) {
|
||||
// For embedded pages, remove the dialog hash key as in getFilePath(),
|
||||
// otherwise the Data Url won't match the id of the embedded Page.
|
||||
// For embedded pages, remove the dialog hash key as in getFilePath(),
|
||||
// otherwise the Data Url won't match the id of the embedded Page.
|
||||
return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
|
||||
} else if ( path.isSameDomain( u, documentBase ) ) {
|
||||
return u.hrefNoHash.replace( documentBase.domain, "" );
|
||||
@ -232,4 +232,4 @@
|
||||
};
|
||||
|
||||
$.path = path;
|
||||
}(jQuery));
|
||||
}(jQuery));
|
||||
|
@ -30,9 +30,9 @@ class FormEncodedDataFormatter extends XMLDataFormatter {
|
||||
}
|
||||
|
||||
public function convertStringToArray($strData) {
|
||||
$postArray = array();
|
||||
parse_str($strData, $postArray);
|
||||
return $postArray;
|
||||
$postArray = array();
|
||||
parse_str($strData, $postArray);
|
||||
return $postArray;
|
||||
//TODO: It would be nice to implement this function in Convert.php
|
||||
//return Convert::querystr2array($strData);
|
||||
}
|
||||
|
@ -106,9 +106,9 @@ class RSSFeed extends ViewableData {
|
||||
* every time the representation does
|
||||
*/
|
||||
public function __construct(SS_List $entries, $link, $title,
|
||||
$description = null, $titleField = "Title",
|
||||
$descriptionField = "Content", $authorField = null,
|
||||
$lastModified = null, $etag = null) {
|
||||
$description = null, $titleField = "Title",
|
||||
$descriptionField = "Content", $authorField = null,
|
||||
$lastModified = null, $etag = null) {
|
||||
$this->entries = $entries;
|
||||
$this->link = $link;
|
||||
$this->description = $description;
|
||||
@ -270,7 +270,7 @@ class RSSFeed_Entry extends ViewableData {
|
||||
* Create a new RSSFeed entry.
|
||||
*/
|
||||
public function __construct($entry, $titleField, $descriptionField,
|
||||
$authorField) {
|
||||
$authorField) {
|
||||
$this->failover = $entry;
|
||||
$this->titleField = $titleField;
|
||||
$this->descriptionField = $descriptionField;
|
||||
|
@ -65,7 +65,7 @@ class RestfulService extends ViewableData {
|
||||
* @param string $password The proxy auth password
|
||||
* @param boolean $socks Set true to use socks5 proxy instead of http
|
||||
*/
|
||||
public function setProxy($proxy, $port = 80, $user = "", $password = "", $socks = false) {
|
||||
public function setProxy($proxy, $port = 80, $user = "", $password = "", $socks = false) {
|
||||
$this->proxy = array(
|
||||
CURLOPT_PROXY => $proxy,
|
||||
CURLOPT_PROXYUSERPWD => "{$user}:{$password}",
|
||||
@ -337,14 +337,14 @@ class RestfulService extends ViewableData {
|
||||
$child_count++;
|
||||
$k = ($parent == "") ? (string)$key : $parent . "_" . (string)$key;
|
||||
if($this->getRecurseValues($value,$data,$k) == 0){ // no childern, aka "leaf node"
|
||||
$conv_value = Convert::raw2xml($value);
|
||||
$conv_value = Convert::raw2xml($value);
|
||||
}
|
||||
//Review the fix for similar node names overriding it's predecessor
|
||||
if(array_key_exists($k, $data) == true) {
|
||||
$data[$k] = $data[$k] . ",". $conv_value;
|
||||
}
|
||||
else {
|
||||
$data[$k] = $conv_value;
|
||||
$data[$k] = $conv_value;
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,19 +37,19 @@ chdir(dirname($_SERVER['SCRIPT_FILENAME']));
|
||||
* fourth => val
|
||||
*/
|
||||
if(isset($_SERVER['argv'][2])) {
|
||||
$args = array_slice($_SERVER['argv'],2);
|
||||
if(!isset($_GET)) $_GET = array();
|
||||
if(!isset($_REQUEST)) $_REQUEST = array();
|
||||
foreach($args as $arg) {
|
||||
if(strpos($arg,'=') == false) {
|
||||
$_GET['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str( (substr($arg,0,2) == '--') ? substr($arg,2) : $arg, $newItems );
|
||||
$_GET = array_merge($_GET, $newItems);
|
||||
}
|
||||
}
|
||||
$_REQUEST = array_merge($_REQUEST, $_GET);
|
||||
$args = array_slice($_SERVER['argv'],2);
|
||||
if(!isset($_GET)) $_GET = array();
|
||||
if(!isset($_REQUEST)) $_REQUEST = array();
|
||||
foreach($args as $arg) {
|
||||
if(strpos($arg,'=') == false) {
|
||||
$_GET['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str( (substr($arg,0,2) == '--') ? substr($arg,2) : $arg, $newItems );
|
||||
$_GET = array_merge($_GET, $newItems);
|
||||
}
|
||||
}
|
||||
$_REQUEST = array_merge($_REQUEST, $_GET);
|
||||
}
|
||||
|
||||
// Set 'url' GET parameter
|
||||
@ -76,7 +76,7 @@ DB::connect($databaseConfig);
|
||||
$url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : null;
|
||||
if(!$url) {
|
||||
echo 'Please specify an argument to cli-script.php/sake. For more information, visit'
|
||||
. ' http://doc.silverstripe.org/framework/en/topics/commandline';
|
||||
. ' http://doc.silverstripe.org/framework/en/topics/commandline';
|
||||
die();
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,8 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) {
|
||||
}
|
||||
|
||||
// For schema enabled drivers:
|
||||
if(defined('SS_DATABASE_SCHEMA'))
|
||||
$databaseConfig["schema"] = SS_DATABASE_SCHEMA;
|
||||
if(defined('SS_DATABASE_SCHEMA'))
|
||||
$databaseConfig["schema"] = SS_DATABASE_SCHEMA;
|
||||
}
|
||||
|
||||
if(defined('SS_SEND_ALL_EMAILS_TO')) {
|
||||
|
@ -45,7 +45,7 @@ class ContentNegotiator {
|
||||
* that need to specify the character set make use of this function.
|
||||
*/
|
||||
public static function get_encoding() {
|
||||
return self::$encoding;
|
||||
return self::$encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +96,7 @@ class ContentNegotiator {
|
||||
} else {
|
||||
// The W3C validator doesn't send an HTTP_ACCEPT header, but it can support xhtml. We put this special
|
||||
// case in here so that designers don't get worried that their templates are HTML4.
|
||||
if(isset($_SERVER['HTTP_USER_AGENT']) && substr($_SERVER['HTTP_USER_AGENT'], 0, 14) == 'W3C_Validator/') {
|
||||
if(isset($_SERVER['HTTP_USER_AGENT']) && substr($_SERVER['HTTP_USER_AGENT'], 0, 14) == 'W3C_Validator/') {
|
||||
$chosenFormat = "xhtml";
|
||||
|
||||
} else {
|
||||
|
@ -164,7 +164,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
|
||||
Debug::message("Request handler $body->class object to $this->class controller;"
|
||||
. "rendering with template returned by $body->class::getViewer()");
|
||||
}
|
||||
$body = $body->getViewer($request->latestParam('Action'))->process($body);
|
||||
$body = $body->getViewer($request->latestParam('Action'))->process($body);
|
||||
}
|
||||
|
||||
$this->response->setBody($body);
|
||||
@ -367,7 +367,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
|
||||
|
||||
return $template->process($obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call this to disable site-wide basic authentication for a specific contoller.
|
||||
* This must be called before Controller::init(). That is, you must call it in your controller's
|
||||
|
@ -348,8 +348,8 @@ class Director implements TemplateGlobalProvider {
|
||||
$url = dirname($_SERVER['REQUEST_URI'] . 'x') . '/' . $url;
|
||||
}
|
||||
|
||||
if(substr($url,0,4) != "http") {
|
||||
if($url[0] != "/") $url = Director::baseURL() . $url;
|
||||
if(substr($url,0,4) != "http") {
|
||||
if($url[0] != "/") $url = Director::baseURL() . $url;
|
||||
// Sometimes baseURL() can return a full URL instead of just a path
|
||||
if(substr($url,0,4) != "http") $url = self::protocolAndHost() . $url;
|
||||
}
|
||||
@ -630,21 +630,21 @@ class Director implements TemplateGlobalProvider {
|
||||
/**
|
||||
* Returns the Absolute URL of the site root.
|
||||
*/
|
||||
public static function absoluteBaseURL() {
|
||||
return Director::absoluteURL(Director::baseURL());
|
||||
}
|
||||
|
||||
public static function absoluteBaseURL() {
|
||||
return Director::absoluteURL(Director::baseURL());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Absolute URL of the site root, embedding the current basic-auth credentials into the URL.
|
||||
*/
|
||||
public static function absoluteBaseURLWithAuth() {
|
||||
public static function absoluteBaseURLWithAuth() {
|
||||
$s = "";
|
||||
$login = "";
|
||||
|
||||
if(isset($_SERVER['PHP_AUTH_USER'])) $login = "$_SERVER[PHP_AUTH_USER]:$_SERVER[PHP_AUTH_PW]@";
|
||||
if(isset($_SERVER['PHP_AUTH_USER'])) $login = "$_SERVER[PHP_AUTH_USER]:$_SERVER[PHP_AUTH_PW]@";
|
||||
|
||||
return Director::protocol() . $login . $_SERVER['HTTP_HOST'] . Director::baseURL();
|
||||
}
|
||||
return Director::protocol() . $login . $_SERVER['HTTP_HOST'] . Director::baseURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the site to run on SSL.
|
||||
@ -843,7 +843,7 @@ class Director implements TemplateGlobalProvider {
|
||||
$result = $_GET['isDev'];
|
||||
} else {
|
||||
if($firstTimeCheckingGetVar && DB::connection_attempted()) {
|
||||
echo "<p style=\"padding: 3px; margin: 3px; background-color: orange;
|
||||
echo "<p style=\"padding: 3px; margin: 3px; background-color: orange;
|
||||
color: white; font-weight: bold\">Sorry, you can't use ?isDev=1 until your
|
||||
Member and Group tables database are available. Perhaps your database
|
||||
connection is failing?</p>";
|
||||
|
@ -171,8 +171,8 @@ class HTTP {
|
||||
if($regexes) foreach($regexes as $regex) {
|
||||
if(preg_match_all($regex, $content, $matches)) {
|
||||
$result = array_merge_recursive($result, (isset($matches[2]) ? $matches[2] : $matches[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count($result) ? $result : null;
|
||||
}
|
||||
|
@ -296,21 +296,21 @@ class SS_HTTPRequest implements ArrayAccess {
|
||||
public function getURL($includeGetVars = false) {
|
||||
$url = ($this->getExtension()) ? $this->url . '.' . $this->getExtension() : $this->url;
|
||||
|
||||
if ($includeGetVars) {
|
||||
// if we don't unset $vars['url'] we end up with /my/url?url=my/url&foo=bar etc
|
||||
|
||||
$vars = $this->getVars();
|
||||
unset($vars['url']);
|
||||
if ($includeGetVars) {
|
||||
// if we don't unset $vars['url'] we end up with /my/url?url=my/url&foo=bar etc
|
||||
|
||||
$vars = $this->getVars();
|
||||
unset($vars['url']);
|
||||
|
||||
if (count($vars)) {
|
||||
$url .= '?' . http_build_query($vars);
|
||||
}
|
||||
}
|
||||
else if(strpos($url, "?") !== false) {
|
||||
$url = substr($url, 0, strpos($url, "?"));
|
||||
}
|
||||
if (count($vars)) {
|
||||
$url .= '?' . http_build_query($vars);
|
||||
}
|
||||
}
|
||||
else if(strpos($url, "?") !== false) {
|
||||
$url = substr($url, 0, strpos($url, "?"));
|
||||
}
|
||||
|
||||
return $url;
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -501,9 +501,9 @@ class SS_HTTPRequest implements ArrayAccess {
|
||||
* @return string
|
||||
*/
|
||||
public function shiftAllParams() {
|
||||
$keys = array_keys($this->allParams);
|
||||
$values = array_values($this->allParams);
|
||||
$value = array_shift($values);
|
||||
$keys = array_keys($this->allParams);
|
||||
$values = array_values($this->allParams);
|
||||
$value = array_shift($values);
|
||||
|
||||
// push additional unparsed URL parts onto the parameter stack
|
||||
if(array_key_exists($this->unshiftedButParsedParts, $this->dirParts)) {
|
||||
@ -636,10 +636,10 @@ class SS_HTTPRequest implements ArrayAccess {
|
||||
*/
|
||||
public function getIP() {
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
//check ip from share internet
|
||||
//check ip from share internet
|
||||
return $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
//to check ip is pass from proxy
|
||||
//to check ip is pass from proxy
|
||||
return $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} elseif(isset($_SERVER['REMOTE_ADDR'])) {
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
@ -655,12 +655,12 @@ class SS_HTTPRequest implements ArrayAccess {
|
||||
* @return array
|
||||
*/
|
||||
public function getAcceptMimetypes($includeQuality = false) {
|
||||
$mimetypes = array();
|
||||
$mimetypesWithQuality = explode(',',$this->getHeader('Accept'));
|
||||
foreach($mimetypesWithQuality as $mimetypeWithQuality) {
|
||||
$mimetypes[] = ($includeQuality) ? $mimetypeWithQuality : preg_replace('/;.*/', '', $mimetypeWithQuality);
|
||||
}
|
||||
return $mimetypes;
|
||||
$mimetypes = array();
|
||||
$mimetypesWithQuality = explode(',',$this->getHeader('Accept'));
|
||||
foreach($mimetypesWithQuality as $mimetypeWithQuality) {
|
||||
$mimetypes[] = ($includeQuality) ? $mimetypeWithQuality : preg_replace('/;.*/', '', $mimetypeWithQuality);
|
||||
}
|
||||
return $mimetypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -303,37 +303,37 @@ class SS_HTTPResponse_Exception extends Exception {
|
||||
* $statusDescription will be the HTTP status of the resulting response.
|
||||
* @see SS_HTTPResponse::__construct();
|
||||
*/
|
||||
public function __construct($body = null, $statusCode = null, $statusDescription = null) {
|
||||
if($body instanceof SS_HTTPResponse) {
|
||||
// statusCode and statusDescription should override whatever is passed in the body
|
||||
if($statusCode) $body->setStatusCode($statusCode);
|
||||
public function __construct($body = null, $statusCode = null, $statusDescription = null) {
|
||||
if($body instanceof SS_HTTPResponse) {
|
||||
// statusCode and statusDescription should override whatever is passed in the body
|
||||
if($statusCode) $body->setStatusCode($statusCode);
|
||||
if($statusDescription) $body->setStatusDescription($statusDescription);
|
||||
|
||||
$this->setResponse($body);
|
||||
} else {
|
||||
} else {
|
||||
$response = new SS_HTTPResponse($body, $statusCode, $statusDescription);
|
||||
|
||||
// Error responses should always be considered plaintext, for security reasons
|
||||
$response->addHeader('Content-Type', 'text/plain');
|
||||
|
||||
$this->setResponse($response);
|
||||
}
|
||||
|
||||
parent::__construct($this->getResponse()->getBody(), $this->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function getResponse() {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SS_HTTPResponse $response
|
||||
*/
|
||||
public function setResponse(SS_HTTPResponse $response) {
|
||||
$this->response = $response;
|
||||
}
|
||||
$this->setResponse($response);
|
||||
}
|
||||
|
||||
parent::__construct($this->getResponse()->getBody(), $this->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function getResponse() {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SS_HTTPResponse $response
|
||||
*/
|
||||
public function setResponse(SS_HTTPResponse $response) {
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ class RequestHandler extends ViewableData {
|
||||
* or by defining $allowed_actions in your {@link Form} class.
|
||||
*/
|
||||
static $allowed_actions = null;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->brokenOnConstruct = false;
|
||||
|
||||
|
@ -36,6 +36,6 @@ class AopProxyService {
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,18 +69,18 @@ class ArrayLib {
|
||||
* @todo Improve documentation
|
||||
*/
|
||||
public static function array_values_recursive($arr) {
|
||||
$lst = array();
|
||||
foreach(array_keys($arr) as $k){
|
||||
$v = $arr[$k];
|
||||
if (is_scalar($v)) {
|
||||
$lst[] = $v;
|
||||
} elseif (is_array($v)) {
|
||||
$lst = array_merge( $lst,
|
||||
self::array_values_recursive($v)
|
||||
);
|
||||
}
|
||||
}
|
||||
return $lst;
|
||||
$lst = array();
|
||||
foreach(array_keys($arr) as $k){
|
||||
$v = $arr[$k];
|
||||
if (is_scalar($v)) {
|
||||
$lst[] = $v;
|
||||
} elseif (is_array($v)) {
|
||||
$lst = array_merge( $lst,
|
||||
self::array_values_recursive($v)
|
||||
);
|
||||
}
|
||||
}
|
||||
return $lst;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,12 +110,12 @@ class ArrayLib {
|
||||
*/
|
||||
public static function is_associative($arr) {
|
||||
if(is_array($arr) && ! empty($arr)) {
|
||||
for($iterator = count($arr) - 1; $iterator; $iterator--) {
|
||||
if (!array_key_exists($iterator, $arr)) return true;
|
||||
}
|
||||
return !array_key_exists(0, $arr);
|
||||
}
|
||||
return false;
|
||||
for($iterator = count($arr) - 1; $iterator; $iterator--) {
|
||||
if (!array_key_exists($iterator, $arr)) return true;
|
||||
}
|
||||
return !array_key_exists(0, $arr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
872
core/Diff.php
872
core/Diff.php
@ -27,21 +27,21 @@ define('USE_ASSERTS', function_exists('assert'));
|
||||
* @access private
|
||||
*/
|
||||
class _DiffOp {
|
||||
var $type;
|
||||
var $orig;
|
||||
var $final;
|
||||
var $type;
|
||||
var $orig;
|
||||
var $final;
|
||||
|
||||
public function reverse() {
|
||||
trigger_error("pure virtual", E_USER_ERROR);
|
||||
}
|
||||
public function reverse() {
|
||||
trigger_error("pure virtual", E_USER_ERROR);
|
||||
}
|
||||
|
||||
public function norig() {
|
||||
return $this->orig ? sizeof($this->orig) : 0;
|
||||
}
|
||||
public function norig() {
|
||||
return $this->orig ? sizeof($this->orig) : 0;
|
||||
}
|
||||
|
||||
public function nfinal() {
|
||||
return $this->final ? sizeof($this->final) : 0;
|
||||
}
|
||||
public function nfinal() {
|
||||
return $this->final ? sizeof($this->final) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,18 +50,18 @@ class _DiffOp {
|
||||
* @access private
|
||||
*/
|
||||
class _DiffOp_Copy extends _DiffOp {
|
||||
var $type = 'copy';
|
||||
var $type = 'copy';
|
||||
|
||||
public function _DiffOp_Copy ($orig, $final = false) {
|
||||
if (!is_array($final))
|
||||
$final = $orig;
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
public function _DiffOp_Copy ($orig, $final = false) {
|
||||
if (!is_array($final))
|
||||
$final = $orig;
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
public function reverse() {
|
||||
return new _DiffOp_Copy($this->final, $this->orig);
|
||||
}
|
||||
public function reverse() {
|
||||
return new _DiffOp_Copy($this->final, $this->orig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,16 +70,16 @@ class _DiffOp_Copy extends _DiffOp {
|
||||
* @access private
|
||||
*/
|
||||
class _DiffOp_Delete extends _DiffOp {
|
||||
var $type = 'delete';
|
||||
var $type = 'delete';
|
||||
|
||||
public function _DiffOp_Delete ($lines) {
|
||||
$this->orig = $lines;
|
||||
$this->final = false;
|
||||
}
|
||||
public function _DiffOp_Delete ($lines) {
|
||||
$this->orig = $lines;
|
||||
$this->final = false;
|
||||
}
|
||||
|
||||
public function reverse() {
|
||||
return new _DiffOp_Add($this->orig);
|
||||
}
|
||||
public function reverse() {
|
||||
return new _DiffOp_Add($this->orig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,16 +88,16 @@ class _DiffOp_Delete extends _DiffOp {
|
||||
* @access private
|
||||
*/
|
||||
class _DiffOp_Add extends _DiffOp {
|
||||
var $type = 'add';
|
||||
var $type = 'add';
|
||||
|
||||
public function _DiffOp_Add ($lines) {
|
||||
$this->final = $lines;
|
||||
$this->orig = false;
|
||||
}
|
||||
public function _DiffOp_Add ($lines) {
|
||||
$this->final = $lines;
|
||||
$this->orig = false;
|
||||
}
|
||||
|
||||
public function reverse() {
|
||||
return new _DiffOp_Delete($this->final);
|
||||
}
|
||||
public function reverse() {
|
||||
return new _DiffOp_Delete($this->final);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,16 +106,16 @@ class _DiffOp_Add extends _DiffOp {
|
||||
* @access private
|
||||
*/
|
||||
class _DiffOp_Change extends _DiffOp {
|
||||
var $type = 'change';
|
||||
var $type = 'change';
|
||||
|
||||
public function _DiffOp_Change ($orig, $final) {
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
public function _DiffOp_Change ($orig, $final) {
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
public function reverse() {
|
||||
return new _DiffOp_Change($this->final, $this->orig);
|
||||
}
|
||||
public function reverse() {
|
||||
return new _DiffOp_Change($this->final, $this->orig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -143,126 +143,126 @@ class _DiffOp_Change extends _DiffOp {
|
||||
*/
|
||||
class _DiffEngine
|
||||
{
|
||||
public function diff ($from_lines, $to_lines) {
|
||||
$n_from = sizeof($from_lines);
|
||||
$n_to = sizeof($to_lines);
|
||||
public function diff ($from_lines, $to_lines) {
|
||||
$n_from = sizeof($from_lines);
|
||||
$n_to = sizeof($to_lines);
|
||||
|
||||
$this->xchanged = $this->ychanged = array();
|
||||
$this->xv = $this->yv = array();
|
||||
$this->xind = $this->yind = array();
|
||||
unset($this->seq);
|
||||
unset($this->in_seq);
|
||||
unset($this->lcs);
|
||||
$this->xchanged = $this->ychanged = array();
|
||||
$this->xv = $this->yv = array();
|
||||
$this->xind = $this->yind = array();
|
||||
unset($this->seq);
|
||||
unset($this->in_seq);
|
||||
unset($this->lcs);
|
||||
|
||||
// Skip leading common lines.
|
||||
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
|
||||
if ($from_lines[$skip] != $to_lines[$skip])
|
||||
break;
|
||||
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
|
||||
}
|
||||
// Skip trailing common lines.
|
||||
$xi = $n_from; $yi = $n_to;
|
||||
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
|
||||
if ($from_lines[$xi] != $to_lines[$yi])
|
||||
break;
|
||||
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
|
||||
}
|
||||
// Skip leading common lines.
|
||||
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
|
||||
if ($from_lines[$skip] != $to_lines[$skip])
|
||||
break;
|
||||
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
|
||||
}
|
||||
// Skip trailing common lines.
|
||||
$xi = $n_from; $yi = $n_to;
|
||||
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
|
||||
if ($from_lines[$xi] != $to_lines[$yi])
|
||||
break;
|
||||
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
|
||||
}
|
||||
|
||||
// Ignore lines which do not exist in both files.
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
|
||||
$xhash[$from_lines[$xi]] = 1;
|
||||
for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
|
||||
$line = $to_lines[$yi];
|
||||
if ( ($this->ychanged[$yi] = empty($xhash[$line])) )
|
||||
continue;
|
||||
$yhash[$line] = 1;
|
||||
$this->yv[] = $line;
|
||||
$this->yind[] = $yi;
|
||||
}
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$line = $from_lines[$xi];
|
||||
if ( ($this->xchanged[$xi] = empty($yhash[$line])) )
|
||||
continue;
|
||||
$this->xv[] = $line;
|
||||
$this->xind[] = $xi;
|
||||
}
|
||||
// Ignore lines which do not exist in both files.
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
|
||||
$xhash[$from_lines[$xi]] = 1;
|
||||
for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
|
||||
$line = $to_lines[$yi];
|
||||
if ( ($this->ychanged[$yi] = empty($xhash[$line])) )
|
||||
continue;
|
||||
$yhash[$line] = 1;
|
||||
$this->yv[] = $line;
|
||||
$this->yind[] = $yi;
|
||||
}
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$line = $from_lines[$xi];
|
||||
if ( ($this->xchanged[$xi] = empty($yhash[$line])) )
|
||||
continue;
|
||||
$this->xv[] = $line;
|
||||
$this->xind[] = $xi;
|
||||
}
|
||||
|
||||
// Find the LCS.
|
||||
$this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
|
||||
// Find the LCS.
|
||||
$this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
|
||||
|
||||
// Merge edits when possible
|
||||
$this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
|
||||
$this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
|
||||
// Merge edits when possible
|
||||
$this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
|
||||
$this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
|
||||
|
||||
// Compute the edit operations.
|
||||
$edits = array();
|
||||
$xi = $yi = 0;
|
||||
while ($xi < $n_from || $yi < $n_to) {
|
||||
USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
|
||||
USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
|
||||
// Compute the edit operations.
|
||||
$edits = array();
|
||||
$xi = $yi = 0;
|
||||
while ($xi < $n_from || $yi < $n_to) {
|
||||
USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
|
||||
USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
|
||||
|
||||
// Skip matching "snake".
|
||||
$copy = array();
|
||||
while ( $xi < $n_from && $yi < $n_to
|
||||
&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
|
||||
$copy[] = $from_lines[$xi++];
|
||||
++$yi;
|
||||
}
|
||||
if ($copy)
|
||||
$edits[] = new _DiffOp_Copy($copy);
|
||||
// Skip matching "snake".
|
||||
$copy = array();
|
||||
while ( $xi < $n_from && $yi < $n_to
|
||||
&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
|
||||
$copy[] = $from_lines[$xi++];
|
||||
++$yi;
|
||||
}
|
||||
if ($copy)
|
||||
$edits[] = new _DiffOp_Copy($copy);
|
||||
|
||||
// Find deletes & adds.
|
||||
$delete = array();
|
||||
while ($xi < $n_from && $this->xchanged[$xi])
|
||||
$delete[] = $from_lines[$xi++];
|
||||
// Find deletes & adds.
|
||||
$delete = array();
|
||||
while ($xi < $n_from && $this->xchanged[$xi])
|
||||
$delete[] = $from_lines[$xi++];
|
||||
|
||||
$add = array();
|
||||
while ($yi < $n_to && $this->ychanged[$yi])
|
||||
$add[] = $to_lines[$yi++];
|
||||
$add = array();
|
||||
while ($yi < $n_to && $this->ychanged[$yi])
|
||||
$add[] = $to_lines[$yi++];
|
||||
|
||||
if ($delete && $add)
|
||||
$edits[] = new _DiffOp_Change($delete, $add);
|
||||
elseif ($delete)
|
||||
$edits[] = new _DiffOp_Delete($delete);
|
||||
elseif ($add)
|
||||
$edits[] = new _DiffOp_Add($add);
|
||||
}
|
||||
return $edits;
|
||||
}
|
||||
if ($delete && $add)
|
||||
$edits[] = new _DiffOp_Change($delete, $add);
|
||||
elseif ($delete)
|
||||
$edits[] = new _DiffOp_Delete($delete);
|
||||
elseif ($add)
|
||||
$edits[] = new _DiffOp_Add($add);
|
||||
}
|
||||
return $edits;
|
||||
}
|
||||
|
||||
|
||||
/* Divide the Largest Common Subsequence (LCS) of the sequences
|
||||
* [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
|
||||
* sized segments.
|
||||
*
|
||||
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an
|
||||
* array of NCHUNKS+1 (X, Y) indexes giving the diving points between
|
||||
* sub sequences. The first sub-sequence is contained in [X0, X1),
|
||||
* [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on. Note
|
||||
* that (X0, Y0) == (XOFF, YOFF) and
|
||||
* (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
|
||||
*
|
||||
* This function assumes that the first lines of the specified portions
|
||||
* of the two files do not match, and likewise that the last lines do not
|
||||
* match. The caller must trim matching lines from the beginning and end
|
||||
* of the portions it is going to specify.
|
||||
*/
|
||||
public function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) {
|
||||
/* Divide the Largest Common Subsequence (LCS) of the sequences
|
||||
* [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
|
||||
* sized segments.
|
||||
*
|
||||
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an
|
||||
* array of NCHUNKS+1 (X, Y) indexes giving the diving points between
|
||||
* sub sequences. The first sub-sequence is contained in [X0, X1),
|
||||
* [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on. Note
|
||||
* that (X0, Y0) == (XOFF, YOFF) and
|
||||
* (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
|
||||
*
|
||||
* This function assumes that the first lines of the specified portions
|
||||
* of the two files do not match, and likewise that the last lines do not
|
||||
* match. The caller must trim matching lines from the beginning and end
|
||||
* of the portions it is going to specify.
|
||||
*/
|
||||
public function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) {
|
||||
$flip = false;
|
||||
|
||||
if ($xlim - $xoff > $ylim - $yoff) {
|
||||
// Things seems faster (I'm not sure I understand why)
|
||||
// when the shortest sequence in X.
|
||||
$flip = true;
|
||||
list ($xoff, $xlim, $yoff, $ylim)
|
||||
// Things seems faster (I'm not sure I understand why)
|
||||
// when the shortest sequence in X.
|
||||
$flip = true;
|
||||
list ($xoff, $xlim, $yoff, $ylim)
|
||||
= array( $yoff, $ylim, $xoff, $xlim);
|
||||
}
|
||||
}
|
||||
|
||||
if ($flip)
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--)
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--)
|
||||
$ymatches[$this->xv[$i]][] = $i;
|
||||
else
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--)
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--)
|
||||
$ymatches[$this->yv[$i]][] = $i;
|
||||
|
||||
$this->lcs = 0;
|
||||
@ -273,70 +273,70 @@ class _DiffEngine
|
||||
$numer = $xlim - $xoff + $nchunks - 1;
|
||||
$x = $xoff;
|
||||
for ($chunk = 0; $chunk < $nchunks; $chunk++) {
|
||||
if ($chunk > 0)
|
||||
if ($chunk > 0)
|
||||
for ($i = 0; $i <= $this->lcs; $i++)
|
||||
$ymids[$i][$chunk-1] = $this->seq[$i];
|
||||
$ymids[$i][$chunk-1] = $this->seq[$i];
|
||||
|
||||
$x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
|
||||
for ( ; $x < $x1; $x++) {
|
||||
$line = $flip ? $this->yv[$x] : $this->xv[$x];
|
||||
if (empty($ymatches[$line]))
|
||||
continue;
|
||||
$x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
|
||||
for ( ; $x < $x1; $x++) {
|
||||
$line = $flip ? $this->yv[$x] : $this->xv[$x];
|
||||
if (empty($ymatches[$line]))
|
||||
continue;
|
||||
$matches = $ymatches[$line];
|
||||
reset($matches);
|
||||
reset($matches);
|
||||
while (list ($junk, $y) = each($matches))
|
||||
if (empty($this->in_seq[$y])) {
|
||||
if (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcs_pos($y);
|
||||
USE_ASSERTS && assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k-1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (list ($junk, $y) = each($matches)) {
|
||||
if ($y > $this->seq[$k-1]) {
|
||||
if ($y > $this->seq[$k-1]) {
|
||||
USE_ASSERTS && assert($y < $this->seq[$k]);
|
||||
// Optimization: this is a common case:
|
||||
// next match is just replacing previous match.
|
||||
$this->in_seq[$this->seq[$k]] = false;
|
||||
$this->seq[$k] = $y;
|
||||
$this->in_seq[$y] = 1;
|
||||
}
|
||||
else if (empty($this->in_seq[$y])) {
|
||||
}
|
||||
else if (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcs_pos($y);
|
||||
USE_ASSERTS && assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
|
||||
$ymid = $ymids[$this->lcs];
|
||||
for ($n = 0; $n < $nchunks - 1; $n++) {
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
|
||||
$y1 = $ymid[$n] + 1;
|
||||
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
|
||||
}
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
|
||||
$y1 = $ymid[$n] + 1;
|
||||
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
|
||||
}
|
||||
$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
|
||||
|
||||
return array($this->lcs, $seps);
|
||||
}
|
||||
}
|
||||
|
||||
public function _lcs_pos ($ypos) {
|
||||
public function _lcs_pos ($ypos) {
|
||||
$end = $this->lcs;
|
||||
if ($end == 0 || $ypos > $this->seq[$end]) {
|
||||
$this->seq[++$this->lcs] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $this->lcs;
|
||||
}
|
||||
$this->seq[++$this->lcs] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $this->lcs;
|
||||
}
|
||||
|
||||
$beg = 1;
|
||||
while ($beg < $end) {
|
||||
$mid = (int)(($beg + $end) / 2);
|
||||
if ( $ypos > $this->seq[$mid] )
|
||||
$mid = (int)(($beg + $end) / 2);
|
||||
if ( $ypos > $this->seq[$mid] )
|
||||
$beg = $mid + 1;
|
||||
else
|
||||
else
|
||||
$end = $mid;
|
||||
}
|
||||
}
|
||||
|
||||
USE_ASSERTS && assert($ypos != $this->seq[$end]);
|
||||
|
||||
@ -344,77 +344,77 @@ class _DiffEngine
|
||||
$this->seq[$end] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find LCS of two sequences.
|
||||
*
|
||||
* The results are recorded in the vectors $this->{x,y}changed[], by
|
||||
* storing a 1 in the element for each line that is an insertion
|
||||
* or deletion (ie. is not in the LCS).
|
||||
*
|
||||
* The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
|
||||
*
|
||||
* Note that XLIM, YLIM are exclusive bounds.
|
||||
* All line numbers are origin-0 and discarded lines are not counted.
|
||||
*/
|
||||
public function _compareseq ($xoff, $xlim, $yoff, $ylim) {
|
||||
/* Find LCS of two sequences.
|
||||
*
|
||||
* The results are recorded in the vectors $this->{x,y}changed[], by
|
||||
* storing a 1 in the element for each line that is an insertion
|
||||
* or deletion (ie. is not in the LCS).
|
||||
*
|
||||
* The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
|
||||
*
|
||||
* Note that XLIM, YLIM are exclusive bounds.
|
||||
* All line numbers are origin-0 and discarded lines are not counted.
|
||||
*/
|
||||
public function _compareseq ($xoff, $xlim, $yoff, $ylim) {
|
||||
// Slide down the bottom initial diagonal.
|
||||
while ($xoff < $xlim && $yoff < $ylim
|
||||
&& $this->xv[$xoff] == $this->yv[$yoff]) {
|
||||
++$xoff;
|
||||
++$yoff;
|
||||
}
|
||||
&& $this->xv[$xoff] == $this->yv[$yoff]) {
|
||||
++$xoff;
|
||||
++$yoff;
|
||||
}
|
||||
|
||||
// Slide up the top initial diagonal.
|
||||
while ($xlim > $xoff && $ylim > $yoff
|
||||
&& $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
|
||||
--$xlim;
|
||||
--$ylim;
|
||||
}
|
||||
&& $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
|
||||
--$xlim;
|
||||
--$ylim;
|
||||
}
|
||||
|
||||
if ($xoff == $xlim || $yoff == $ylim)
|
||||
$lcs = 0;
|
||||
$lcs = 0;
|
||||
else {
|
||||
// This is ad hoc but seems to work well.
|
||||
//$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
|
||||
//$nchunks = max(2,min(8,(int)$nchunks));
|
||||
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
|
||||
list ($lcs, $seps)
|
||||
// This is ad hoc but seems to work well.
|
||||
//$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
|
||||
//$nchunks = max(2,min(8,(int)$nchunks));
|
||||
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
|
||||
list ($lcs, $seps)
|
||||
= $this->_diag($xoff,$xlim,$yoff, $ylim,$nchunks);
|
||||
}
|
||||
}
|
||||
|
||||
if ($lcs == 0) {
|
||||
// X and Y sequences have no common subsequence:
|
||||
// mark all changed.
|
||||
while ($yoff < $ylim)
|
||||
// X and Y sequences have no common subsequence:
|
||||
// mark all changed.
|
||||
while ($yoff < $ylim)
|
||||
$this->ychanged[$this->yind[$yoff++]] = 1;
|
||||
while ($xoff < $xlim)
|
||||
while ($xoff < $xlim)
|
||||
$this->xchanged[$this->xind[$xoff++]] = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use the partitions to split this problem into subproblems.
|
||||
reset($seps);
|
||||
$pt1 = $seps[0];
|
||||
while ($pt2 = next($seps)) {
|
||||
// Use the partitions to split this problem into subproblems.
|
||||
reset($seps);
|
||||
$pt1 = $seps[0];
|
||||
while ($pt2 = next($seps)) {
|
||||
$this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
|
||||
$pt1 = $pt2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust inserts/deletes of identical lines to join changes
|
||||
* as much as possible.
|
||||
*
|
||||
* We do something when a run of changed lines include a
|
||||
* line at one end and has an excluded, identical line at the other.
|
||||
* We are free to choose which identical line is included.
|
||||
* 'compareseq' usually chooses the one at the beginning,
|
||||
* but usually it is cleaner to consider the following identical line
|
||||
* to be the "change".
|
||||
*
|
||||
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
|
||||
*/
|
||||
public function _shift_boundaries ($lines, &$changed, $other_changed) {
|
||||
/* Adjust inserts/deletes of identical lines to join changes
|
||||
* as much as possible.
|
||||
*
|
||||
* We do something when a run of changed lines include a
|
||||
* line at one end and has an excluded, identical line at the other.
|
||||
* We are free to choose which identical line is included.
|
||||
* 'compareseq' usually chooses the one at the beginning,
|
||||
* but usually it is cleaner to consider the following identical line
|
||||
* to be the "change".
|
||||
*
|
||||
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
|
||||
*/
|
||||
public function _shift_boundaries ($lines, &$changed, $other_changed) {
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
|
||||
@ -423,37 +423,37 @@ class _DiffEngine
|
||||
$other_len = sizeof($other_changed);
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Scan forwards to find beginning of another run of changes.
|
||||
* Also keep track of the corresponding point in the other file.
|
||||
*
|
||||
* Throughout this code, $i and $j are adjusted together so that
|
||||
* the first $i elements of $changed and the first $j elements
|
||||
* of $other_changed both contain the same number of zeros
|
||||
* (unchanged lines).
|
||||
* Furthermore, $j is always kept so that $j == $other_len or
|
||||
* $other_changed[$j] == false.
|
||||
*/
|
||||
while ($j < $other_len && $other_changed[$j])
|
||||
/*
|
||||
* Scan forwards to find beginning of another run of changes.
|
||||
* Also keep track of the corresponding point in the other file.
|
||||
*
|
||||
* Throughout this code, $i and $j are adjusted together so that
|
||||
* the first $i elements of $changed and the first $j elements
|
||||
* of $other_changed both contain the same number of zeros
|
||||
* (unchanged lines).
|
||||
* Furthermore, $j is always kept so that $j == $other_len or
|
||||
* $other_changed[$j] == false.
|
||||
*/
|
||||
while ($j < $other_len && $other_changed[$j])
|
||||
$j++;
|
||||
|
||||
while ($i < $len && ! $changed[$i]) {
|
||||
while ($i < $len && ! $changed[$i]) {
|
||||
USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
|
||||
$i++; $j++;
|
||||
while ($j < $other_len && $other_changed[$j])
|
||||
$j++;
|
||||
}
|
||||
$j++;
|
||||
}
|
||||
|
||||
if ($i == $len)
|
||||
if ($i == $len)
|
||||
break;
|
||||
|
||||
$start = $i;
|
||||
$start = $i;
|
||||
|
||||
// Find the end of this run of changes.
|
||||
while (++$i < $len && $changed[$i])
|
||||
// Find the end of this run of changes.
|
||||
while (++$i < $len && $changed[$i])
|
||||
continue;
|
||||
|
||||
do {
|
||||
do {
|
||||
/*
|
||||
* Record the length of this run of changes, so that
|
||||
* we can later determine whether the run has grown.
|
||||
@ -466,15 +466,15 @@ class _DiffEngine
|
||||
* This merges with previous changed regions.
|
||||
*/
|
||||
while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = false;
|
||||
while ($start > 0 && $changed[$start - 1])
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = false;
|
||||
while ($start > 0 && $changed[$start - 1])
|
||||
$start--;
|
||||
USE_ASSERTS && assert('$j > 0');
|
||||
while ($other_changed[--$j])
|
||||
USE_ASSERTS && assert('$j > 0');
|
||||
while ($other_changed[--$j])
|
||||
continue;
|
||||
USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
|
||||
}
|
||||
USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
|
||||
}
|
||||
|
||||
/*
|
||||
* Set CORRESPONDING to the end of the changed run, at the last
|
||||
@ -491,35 +491,35 @@ class _DiffEngine
|
||||
* the changed region is moved forward as far as possible.
|
||||
*/
|
||||
while ($i < $len && $lines[$start] == $lines[$i]) {
|
||||
$changed[$start++] = false;
|
||||
$changed[$i++] = 1;
|
||||
while ($i < $len && $changed[$i])
|
||||
$changed[$start++] = false;
|
||||
$changed[$i++] = 1;
|
||||
while ($i < $len && $changed[$i])
|
||||
$i++;
|
||||
|
||||
USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
|
||||
$j++;
|
||||
if ($j < $other_len && $other_changed[$j]) {
|
||||
USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
|
||||
$j++;
|
||||
if ($j < $other_len && $other_changed[$j]) {
|
||||
$corresponding = $i;
|
||||
while ($j < $other_len && $other_changed[$j])
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
} while ($runlength != $i - $start);
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
} while ($runlength != $i - $start);
|
||||
|
||||
/*
|
||||
* If possible, move the fully-merged run of changes
|
||||
* back to a corresponding run in the other file.
|
||||
*/
|
||||
while ($corresponding < $i) {
|
||||
/*
|
||||
* If possible, move the fully-merged run of changes
|
||||
* back to a corresponding run in the other file.
|
||||
*/
|
||||
while ($corresponding < $i) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = 0;
|
||||
USE_ASSERTS && assert('$j > 0');
|
||||
while ($other_changed[--$j])
|
||||
continue;
|
||||
continue;
|
||||
USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,138 +531,138 @@ class Diff
|
||||
{
|
||||
public static $html_cleaner_class = null;
|
||||
|
||||
var $edits;
|
||||
var $edits;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Computes diff between sequences of strings.
|
||||
*
|
||||
* @param $from_lines array An array of strings.
|
||||
* (Typically these are lines from a file.)
|
||||
* @param $to_lines array An array of strings.
|
||||
*/
|
||||
public function Diff($from_lines, $to_lines) {
|
||||
$eng = new _DiffEngine;
|
||||
$this->edits = $eng->diff($from_lines, $to_lines);
|
||||
//$this->_check($from_lines, $to_lines);
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
* Computes diff between sequences of strings.
|
||||
*
|
||||
* @param $from_lines array An array of strings.
|
||||
* (Typically these are lines from a file.)
|
||||
* @param $to_lines array An array of strings.
|
||||
*/
|
||||
public function Diff($from_lines, $to_lines) {
|
||||
$eng = new _DiffEngine;
|
||||
$this->edits = $eng->diff($from_lines, $to_lines);
|
||||
//$this->_check($from_lines, $to_lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute reversed Diff.
|
||||
*
|
||||
* SYNOPSIS:
|
||||
*
|
||||
* $diff = new Diff($lines1, $lines2);
|
||||
* $rev = $diff->reverse();
|
||||
* @return object A Diff object representing the inverse of the
|
||||
* original diff.
|
||||
*/
|
||||
public function reverse () {
|
||||
/**
|
||||
* Compute reversed Diff.
|
||||
*
|
||||
* SYNOPSIS:
|
||||
*
|
||||
* $diff = new Diff($lines1, $lines2);
|
||||
* $rev = $diff->reverse();
|
||||
* @return object A Diff object representing the inverse of the
|
||||
* original diff.
|
||||
*/
|
||||
public function reverse () {
|
||||
$rev = $this;
|
||||
$rev->edits = array();
|
||||
foreach ($this->edits as $edit) {
|
||||
$rev->edits[] = $edit->reverse();
|
||||
}
|
||||
$rev->edits = array();
|
||||
foreach ($this->edits as $edit) {
|
||||
$rev->edits[] = $edit->reverse();
|
||||
}
|
||||
return $rev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for empty diff.
|
||||
*
|
||||
* @return bool True iff two sequences were identical.
|
||||
*/
|
||||
public function isEmpty () {
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->type != 'copy')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Check for empty diff.
|
||||
*
|
||||
* @return bool True iff two sequences were identical.
|
||||
*/
|
||||
public function isEmpty () {
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->type != 'copy')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the length of the Longest Common Subsequence (LCS).
|
||||
*
|
||||
* This is mostly for diagnostic purposed.
|
||||
*
|
||||
* @return int The length of the LCS.
|
||||
*/
|
||||
public function lcs () {
|
||||
/**
|
||||
* Compute the length of the Longest Common Subsequence (LCS).
|
||||
*
|
||||
* This is mostly for diagnostic purposed.
|
||||
*
|
||||
* @return int The length of the LCS.
|
||||
*/
|
||||
public function lcs () {
|
||||
$lcs = 0;
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->type == 'copy')
|
||||
$lcs += sizeof($edit->orig);
|
||||
}
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->type == 'copy')
|
||||
$lcs += sizeof($edit->orig);
|
||||
}
|
||||
return $lcs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original set of lines.
|
||||
*
|
||||
* This reconstructs the $from_lines parameter passed to the
|
||||
* constructor.
|
||||
*
|
||||
* @return array The original sequence of strings.
|
||||
*/
|
||||
public function orig() {
|
||||
$lines = array();
|
||||
/**
|
||||
* Get the original set of lines.
|
||||
*
|
||||
* This reconstructs the $from_lines parameter passed to the
|
||||
* constructor.
|
||||
*
|
||||
* @return array The original sequence of strings.
|
||||
*/
|
||||
public function orig() {
|
||||
$lines = array();
|
||||
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->orig)
|
||||
array_splice($lines, sizeof($lines), 0, $edit->orig);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->orig)
|
||||
array_splice($lines, sizeof($lines), 0, $edit->orig);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the final set of lines.
|
||||
*
|
||||
* This reconstructs the $to_lines parameter passed to the
|
||||
* constructor.
|
||||
*
|
||||
* @return array The sequence of strings.
|
||||
*/
|
||||
public function finaltext() {
|
||||
$lines = array();
|
||||
/**
|
||||
* Get the final set of lines.
|
||||
*
|
||||
* This reconstructs the $to_lines parameter passed to the
|
||||
* constructor.
|
||||
*
|
||||
* @return array The sequence of strings.
|
||||
*/
|
||||
public function finaltext() {
|
||||
$lines = array();
|
||||
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->final)
|
||||
array_splice($lines, sizeof($lines), 0, $edit->final);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
foreach ($this->edits as $edit) {
|
||||
if ($edit->final)
|
||||
array_splice($lines, sizeof($lines), 0, $edit->final);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a Diff for validity.
|
||||
*
|
||||
* This is here only for debugging purposes.
|
||||
*/
|
||||
public function _check ($from_lines, $to_lines) {
|
||||
if (serialize($from_lines) != serialize($this->orig()))
|
||||
trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
|
||||
if (serialize($to_lines) != serialize($this->finaltext()))
|
||||
trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
|
||||
/**
|
||||
* Check a Diff for validity.
|
||||
*
|
||||
* This is here only for debugging purposes.
|
||||
*/
|
||||
public function _check ($from_lines, $to_lines) {
|
||||
if (serialize($from_lines) != serialize($this->orig()))
|
||||
trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
|
||||
if (serialize($to_lines) != serialize($this->finaltext()))
|
||||
trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
|
||||
|
||||
$rev = $this->reverse();
|
||||
if (serialize($to_lines) != serialize($rev->orig()))
|
||||
trigger_error("Reversed original doesn't match", E_USER_ERROR);
|
||||
if (serialize($from_lines) != serialize($rev->finaltext()))
|
||||
trigger_error("Reversed final doesn't match", E_USER_ERROR);
|
||||
$rev = $this->reverse();
|
||||
if (serialize($to_lines) != serialize($rev->orig()))
|
||||
trigger_error("Reversed original doesn't match", E_USER_ERROR);
|
||||
if (serialize($from_lines) != serialize($rev->finaltext()))
|
||||
trigger_error("Reversed final doesn't match", E_USER_ERROR);
|
||||
|
||||
|
||||
$prevtype = 'none';
|
||||
foreach ($this->edits as $edit) {
|
||||
if ( $prevtype == $edit->type )
|
||||
trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
|
||||
$prevtype = $edit->type;
|
||||
}
|
||||
$prevtype = 'none';
|
||||
foreach ($this->edits as $edit) {
|
||||
if ( $prevtype == $edit->type )
|
||||
trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
|
||||
$prevtype = $edit->type;
|
||||
}
|
||||
|
||||
$lcs = $this->lcs();
|
||||
trigger_error("Diff okay: LCS = $lcs", E_USER_NOTICE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
$lcs = $this->lcs();
|
||||
trigger_error("Diff okay: LCS = $lcs", E_USER_NOTICE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to clean invalid HTML, which messes up diffs.
|
||||
* This cleans code if possible, using an instance of HTMLCleaner
|
||||
*
|
||||
@ -750,7 +750,7 @@ class Diff
|
||||
else $rechunked[$listName][] = $item;
|
||||
|
||||
if($lookForTag && !$tagStack[$listName] && isset($item[0]) && $item[0] == "<"
|
||||
&& substr($item,0,2) != "</") {
|
||||
&& substr($item,0,2) != "</") {
|
||||
$tagStack[$listName] = 1;
|
||||
} else if($tagStack[$listName]) {
|
||||
if(substr($item,0,2) == "</") $tagStack[$listName]--;
|
||||
@ -830,54 +830,54 @@ class Diff
|
||||
class MappedDiff
|
||||
extends Diff
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Computes diff between sequences of strings.
|
||||
*
|
||||
* This can be used to compute things like
|
||||
* case-insensitve diffs, or diffs which ignore
|
||||
* changes in white-space.
|
||||
*
|
||||
* @param $from_lines array An array of strings.
|
||||
* (Typically these are lines from a file.)
|
||||
*
|
||||
* @param $to_lines array An array of strings.
|
||||
*
|
||||
* @param $mapped_from_lines array This array should
|
||||
* have the same size number of elements as $from_lines.
|
||||
* The elements in $mapped_from_lines and
|
||||
* $mapped_to_lines are what is actually compared
|
||||
* when computing the diff.
|
||||
*
|
||||
* @param $mapped_to_lines array This array should
|
||||
* have the same number of elements as $to_lines.
|
||||
*/
|
||||
public function MappedDiff($from_lines, $to_lines,
|
||||
$mapped_from_lines, $mapped_to_lines) {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Computes diff between sequences of strings.
|
||||
*
|
||||
* This can be used to compute things like
|
||||
* case-insensitve diffs, or diffs which ignore
|
||||
* changes in white-space.
|
||||
*
|
||||
* @param $from_lines array An array of strings.
|
||||
* (Typically these are lines from a file.)
|
||||
*
|
||||
* @param $to_lines array An array of strings.
|
||||
*
|
||||
* @param $mapped_from_lines array This array should
|
||||
* have the same size number of elements as $from_lines.
|
||||
* The elements in $mapped_from_lines and
|
||||
* $mapped_to_lines are what is actually compared
|
||||
* when computing the diff.
|
||||
*
|
||||
* @param $mapped_to_lines array This array should
|
||||
* have the same number of elements as $to_lines.
|
||||
*/
|
||||
public function MappedDiff($from_lines, $to_lines,
|
||||
$mapped_from_lines, $mapped_to_lines) {
|
||||
|
||||
assert(sizeof($from_lines) == sizeof($mapped_from_lines));
|
||||
assert(sizeof($to_lines) == sizeof($mapped_to_lines));
|
||||
assert(sizeof($from_lines) == sizeof($mapped_from_lines));
|
||||
assert(sizeof($to_lines) == sizeof($mapped_to_lines));
|
||||
|
||||
$this->Diff($mapped_from_lines, $mapped_to_lines);
|
||||
$this->Diff($mapped_from_lines, $mapped_to_lines);
|
||||
|
||||
$xi = $yi = 0;
|
||||
// Optimizing loop invariants:
|
||||
// http://phplens.com/lens/php-book/optimizing-debugging-php.php
|
||||
for ($i = 0, $max = sizeof($this->edits); $i < $max; $i++) {
|
||||
$orig = &$this->edits[$i]->orig;
|
||||
if (is_array($orig)) {
|
||||
$orig = array_slice($from_lines, $xi, sizeof($orig));
|
||||
$xi += sizeof($orig);
|
||||
}
|
||||
$xi = $yi = 0;
|
||||
// Optimizing loop invariants:
|
||||
// http://phplens.com/lens/php-book/optimizing-debugging-php.php
|
||||
for ($i = 0, $max = sizeof($this->edits); $i < $max; $i++) {
|
||||
$orig = &$this->edits[$i]->orig;
|
||||
if (is_array($orig)) {
|
||||
$orig = array_slice($from_lines, $xi, sizeof($orig));
|
||||
$xi += sizeof($orig);
|
||||
}
|
||||
|
||||
$final = &$this->edits[$i]->final;
|
||||
if (is_array($final)) {
|
||||
$final = array_slice($to_lines, $yi, sizeof($final));
|
||||
$yi += sizeof($final);
|
||||
}
|
||||
}
|
||||
}
|
||||
$final = &$this->edits[$i]->final;
|
||||
if (is_array($final)) {
|
||||
$final = array_slice($to_lines, $yi, sizeof($final));
|
||||
$yi += sizeof($final);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,7 +140,7 @@ abstract class BulkLoader extends ViewableData {
|
||||
|
||||
//get all instances of the to be imported data object
|
||||
if($this->deleteExistingRecords) {
|
||||
DataObject::get($this->objectClass)->removeAll();
|
||||
DataObject::get($this->objectClass)->removeAll();
|
||||
}
|
||||
|
||||
return $this->processAll($filepath);
|
||||
@ -273,12 +273,12 @@ class BulkLoader_Result extends Object {
|
||||
* </code>
|
||||
*/
|
||||
protected $created = array();
|
||||
|
||||
|
||||
/**
|
||||
* @var array (see {@link $created})
|
||||
*/
|
||||
protected $updated = array();
|
||||
|
||||
|
||||
/**
|
||||
* @var array (see {@link $created})
|
||||
*/
|
||||
@ -290,7 +290,7 @@ class BulkLoader_Result extends Object {
|
||||
* one of 3 strings: "created", "updated", or "deleted"
|
||||
*/
|
||||
protected $lastChange = array();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the count of all objects which were
|
||||
* created or updated.
|
||||
@ -408,5 +408,4 @@ class BulkLoader_Result extends Object {
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,15 +18,15 @@ class DevelopmentAdmin extends Controller {
|
||||
);
|
||||
|
||||
static $allowed_actions = array(
|
||||
'index',
|
||||
'tests',
|
||||
'jstests',
|
||||
'tasks',
|
||||
'viewmodel',
|
||||
'build',
|
||||
'reset',
|
||||
'viewcode'
|
||||
);
|
||||
'index',
|
||||
'tests',
|
||||
'jstests',
|
||||
'tasks',
|
||||
'viewmodel',
|
||||
'build',
|
||||
'reset',
|
||||
'viewcode'
|
||||
);
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
@ -56,7 +56,7 @@ class DevelopmentAdmin extends Controller {
|
||||
$matched = false;
|
||||
if(isset($_FILE_TO_URL_MAPPING[$testPath])) {
|
||||
$matched = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
$testPath = dirname($testPath);
|
||||
}
|
||||
|
@ -8,14 +8,14 @@
|
||||
*
|
||||
* <code>
|
||||
* public function testMyForm() {
|
||||
* // Visit a URL
|
||||
* $this->get("your/url");
|
||||
* // Visit a URL
|
||||
* $this->get("your/url");
|
||||
*
|
||||
* // Submit a form on the page that you get in response
|
||||
* $this->submitForm("MyForm_ID", array("Email" => "invalid email ^&*&^"));
|
||||
* // Submit a form on the page that you get in response
|
||||
* $this->submitForm("MyForm_ID", array("Email" => "invalid email ^&*&^"));
|
||||
*
|
||||
* // Validate the content that is returned
|
||||
* $this->assertExactMatchBySelector("#MyForm_ID p.error", array("That email address is invalid."));
|
||||
* // Validate the content that is returned
|
||||
* $this->assertExactMatchBySelector("#MyForm_ID p.error", array("That email address is invalid."));
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
@ -70,10 +70,10 @@ class FunctionalTest extends SapphireTest {
|
||||
if($this->stat('use_draft_site')) {
|
||||
$this->useDraftSite();
|
||||
}
|
||||
|
||||
// Unprotect the site, tests are running with the assumption it's off. They will enable it on a case-by-case
|
||||
// basis.
|
||||
BasicAuth::protect_entire_site(false);
|
||||
|
||||
// Unprotect the site, tests are running with the assumption it's off. They will enable it on a case-by-case
|
||||
// basis.
|
||||
BasicAuth::protect_entire_site(false);
|
||||
|
||||
SecurityToken::disable();
|
||||
}
|
||||
@ -193,8 +193,8 @@ class FunctionalTest extends SapphireTest {
|
||||
foreach($expectedMatches as $match) {
|
||||
$this->assertTrue(
|
||||
isset($actuals[$match]),
|
||||
"Failed asserting the CSS selector '$selector' has a partial match to the expected elements:\n'"
|
||||
. implode("'\n'", $expectedMatches) . "'\n\n"
|
||||
"Failed asserting the CSS selector '$selector' has a partial match to the expected elements:\n'"
|
||||
. implode("'\n'", $expectedMatches) . "'\n\n"
|
||||
. "Instead the following elements were found:\n'" . implode("'\n'", array_keys($actuals)) . "'"
|
||||
);
|
||||
return false;
|
||||
|
394
dev/Profiler.php
394
dev/Profiler.php
@ -16,224 +16,224 @@
|
||||
* @subpackage misc
|
||||
*/
|
||||
class Profiler {
|
||||
var $description;
|
||||
var $startTime;
|
||||
var $endTime;
|
||||
var $initTime;
|
||||
var $cur_timer;
|
||||
var $stack;
|
||||
var $trail;
|
||||
var $trace;
|
||||
var $count;
|
||||
var $running;
|
||||
|
||||
protected static $inst;
|
||||
var $description;
|
||||
var $startTime;
|
||||
var $endTime;
|
||||
var $initTime;
|
||||
var $cur_timer;
|
||||
var $stack;
|
||||
var $trail;
|
||||
var $trace;
|
||||
var $count;
|
||||
var $running;
|
||||
|
||||
protected static $inst;
|
||||
|
||||
/**
|
||||
* Initialise the timer. with the current micro time
|
||||
*/
|
||||
public function Profiler( $output_enabled=false, $trace_enabled=false)
|
||||
{
|
||||
$this->description = array();
|
||||
$this->startTime = array();
|
||||
$this->endTime = array();
|
||||
$this->initTime = 0;
|
||||
$this->cur_timer = "";
|
||||
$this->stack = array();
|
||||
$this->trail = "";
|
||||
$this->trace = "";
|
||||
$this->count = array();
|
||||
$this->running = array();
|
||||
$this->initTime = $this->getMicroTime();
|
||||
$this->output_enabled = $output_enabled;
|
||||
$this->trace_enabled = $trace_enabled;
|
||||
$this->startTimer('unprofiled');
|
||||
}
|
||||
/**
|
||||
* Initialise the timer. with the current micro time
|
||||
*/
|
||||
public function Profiler( $output_enabled=false, $trace_enabled=false)
|
||||
{
|
||||
$this->description = array();
|
||||
$this->startTime = array();
|
||||
$this->endTime = array();
|
||||
$this->initTime = 0;
|
||||
$this->cur_timer = "";
|
||||
$this->stack = array();
|
||||
$this->trail = "";
|
||||
$this->trace = "";
|
||||
$this->count = array();
|
||||
$this->running = array();
|
||||
$this->initTime = $this->getMicroTime();
|
||||
$this->output_enabled = $output_enabled;
|
||||
$this->trace_enabled = $trace_enabled;
|
||||
$this->startTimer('unprofiled');
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
|
||||
public static function init() {
|
||||
Deprecation::notice('3.1', 'The Profiler class is deprecated, use third party tools like XHProf instead');
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
}
|
||||
|
||||
public static function mark($name, $level2 = "", $desc = "") {
|
||||
if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
|
||||
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
self::$inst->startTimer($name, $desc);
|
||||
}
|
||||
public static function unmark($name, $level2 = "", $desc = "") {
|
||||
if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
|
||||
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
self::$inst->stopTimer($name, $desc);
|
||||
}
|
||||
public static function show($showTrace = false) {
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
echo "<div style=\"position: absolute; z-index: 100000; top: 20px; left: 20px; background-color: white;"
|
||||
. " padding: 20px; border: 1px #AAA solid; height: 80%; overflow: auto;\">";
|
||||
echo "<p><a href=\"#\" onclick=\"this.parentNode.parentNode.style.display = 'none'; return false;\">"
|
||||
. "(Click to close)</a></p>";
|
||||
self::$inst->printTimers();
|
||||
if($showTrace) self::$inst->printTrace();
|
||||
echo "</div>";
|
||||
}
|
||||
// Public Methods
|
||||
|
||||
public static function init() {
|
||||
Deprecation::notice('3.1', 'The Profiler class is deprecated, use third party tools like XHProf instead');
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
}
|
||||
|
||||
public static function mark($name, $level2 = "", $desc = "") {
|
||||
if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
|
||||
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
self::$inst->startTimer($name, $desc);
|
||||
}
|
||||
public static function unmark($name, $level2 = "", $desc = "") {
|
||||
if($level2 && $_GET['debug_profile'] > 1) $name .= " $level2";
|
||||
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
self::$inst->stopTimer($name, $desc);
|
||||
}
|
||||
public static function show($showTrace = false) {
|
||||
if(!self::$inst) self::$inst = new Profiler(true,true);
|
||||
|
||||
echo "<div style=\"position: absolute; z-index: 100000; top: 20px; left: 20px; background-color: white;"
|
||||
. " padding: 20px; border: 1px #AAA solid; height: 80%; overflow: auto;\">";
|
||||
echo "<p><a href=\"#\" onclick=\"this.parentNode.parentNode.style.display = 'none'; return false;\">"
|
||||
. "(Click to close)</a></p>";
|
||||
self::$inst->printTimers();
|
||||
if($showTrace) self::$inst->printTrace();
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an individual timer
|
||||
* This will pause the running timer and place it on a stack.
|
||||
* @param string $name name of the timer
|
||||
* @param string optional $desc description of the timer
|
||||
*/
|
||||
public function startTimer($name, $desc="" ){
|
||||
$this->trace.="start $name\n";
|
||||
$n=array_push( $this->stack, $this->cur_timer );
|
||||
$this->__suspendTimer( $this->stack[$n-1] );
|
||||
$this->startTime[$name] = $this->getMicroTime();
|
||||
$this->cur_timer=$name;
|
||||
$this->description[$name] = $desc;
|
||||
if (!array_key_exists($name,$this->count))
|
||||
$this->count[$name] = 1;
|
||||
else
|
||||
$this->count[$name]++;
|
||||
}
|
||||
/**
|
||||
* Start an individual timer
|
||||
* This will pause the running timer and place it on a stack.
|
||||
* @param string $name name of the timer
|
||||
* @param string optional $desc description of the timer
|
||||
*/
|
||||
public function startTimer($name, $desc="" ){
|
||||
$this->trace.="start $name\n";
|
||||
$n=array_push( $this->stack, $this->cur_timer );
|
||||
$this->__suspendTimer( $this->stack[$n-1] );
|
||||
$this->startTime[$name] = $this->getMicroTime();
|
||||
$this->cur_timer=$name;
|
||||
$this->description[$name] = $desc;
|
||||
if (!array_key_exists($name,$this->count))
|
||||
$this->count[$name] = 1;
|
||||
else
|
||||
$this->count[$name]++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop an individual timer
|
||||
* Restart the timer that was running before this one
|
||||
* @param string $name name of the timer
|
||||
*/
|
||||
public function stopTimer($name){
|
||||
$this->trace.="stop $name\n";
|
||||
$this->endTime[$name] = $this->getMicroTime();
|
||||
if (!array_key_exists($name, $this->running))
|
||||
$this->running[$name] = $this->elapsedTime($name);
|
||||
else
|
||||
$this->running[$name] += $this->elapsedTime($name);
|
||||
$this->cur_timer=array_pop($this->stack);
|
||||
$this->__resumeTimer($this->cur_timer);
|
||||
}
|
||||
/**
|
||||
* Stop an individual timer
|
||||
* Restart the timer that was running before this one
|
||||
* @param string $name name of the timer
|
||||
*/
|
||||
public function stopTimer($name){
|
||||
$this->trace.="stop $name\n";
|
||||
$this->endTime[$name] = $this->getMicroTime();
|
||||
if (!array_key_exists($name, $this->running))
|
||||
$this->running[$name] = $this->elapsedTime($name);
|
||||
else
|
||||
$this->running[$name] += $this->elapsedTime($name);
|
||||
$this->cur_timer=array_pop($this->stack);
|
||||
$this->__resumeTimer($this->cur_timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* measure the elapsed time of a timer without stoping the timer if
|
||||
* it is still running
|
||||
*/
|
||||
public function elapsedTime($name){
|
||||
// This shouldn't happen, but it does once.
|
||||
if (!array_key_exists($name,$this->startTime))
|
||||
return 0;
|
||||
/**
|
||||
* measure the elapsed time of a timer without stoping the timer if
|
||||
* it is still running
|
||||
*/
|
||||
public function elapsedTime($name){
|
||||
// This shouldn't happen, but it does once.
|
||||
if (!array_key_exists($name,$this->startTime))
|
||||
return 0;
|
||||
|
||||
if(array_key_exists($name,$this->endTime)){
|
||||
return ($this->endTime[$name] - $this->startTime[$name]);
|
||||
} else {
|
||||
$now=$this->getMicroTime();
|
||||
return ($now - $this->startTime[$name]);
|
||||
}
|
||||
}//end start_time
|
||||
if(array_key_exists($name,$this->endTime)){
|
||||
return ($this->endTime[$name] - $this->startTime[$name]);
|
||||
} else {
|
||||
$now=$this->getMicroTime();
|
||||
return ($now - $this->startTime[$name]);
|
||||
}
|
||||
}//end start_time
|
||||
|
||||
/**
|
||||
* Measure the elapsed time since the profile class was initialised
|
||||
*
|
||||
*/
|
||||
public function elapsedOverall(){
|
||||
$oaTime = $this->getMicroTime() - $this->initTime;
|
||||
return($oaTime);
|
||||
}//end start_time
|
||||
/**
|
||||
* Measure the elapsed time since the profile class was initialised
|
||||
*
|
||||
*/
|
||||
public function elapsedOverall(){
|
||||
$oaTime = $this->getMicroTime() - $this->initTime;
|
||||
return($oaTime);
|
||||
}//end start_time
|
||||
|
||||
/**
|
||||
* print out a log of all the timers that were registered
|
||||
*
|
||||
*/
|
||||
public function printTimers($enabled=false)
|
||||
{
|
||||
if($this->output_enabled||$enabled){
|
||||
$TimedTotal = 0;
|
||||
$tot_perc = 0;
|
||||
ksort($this->description);
|
||||
print("<pre>\n");
|
||||
$oaTime = $this->getMicroTime() - $this->initTime;
|
||||
echo"============================================================================\n";
|
||||
echo " PROFILER OUTPUT\n";
|
||||
echo"============================================================================\n";
|
||||
print( "Calls Time Routine\n");
|
||||
echo"-----------------------------------------------------------------------------\n";
|
||||
while (list ($key, $val) = each ($this->description)) {
|
||||
$t = $this->elapsedTime($key);
|
||||
$total = $this->running[$key];
|
||||
$count = $this->count[$key];
|
||||
$TimedTotal += $total;
|
||||
$perc = ($total/$oaTime)*100;
|
||||
$tot_perc+=$perc;
|
||||
// $perc=sprintf("%3.2f", $perc );
|
||||
$lines[ sprintf( "%3d %3.4f ms (%3.2f %%) %s\n", $count, $total*1000, $perc, $key) ] = $total;
|
||||
}
|
||||
/**
|
||||
* print out a log of all the timers that were registered
|
||||
*
|
||||
*/
|
||||
public function printTimers($enabled=false)
|
||||
{
|
||||
if($this->output_enabled||$enabled){
|
||||
$TimedTotal = 0;
|
||||
$tot_perc = 0;
|
||||
ksort($this->description);
|
||||
print("<pre>\n");
|
||||
$oaTime = $this->getMicroTime() - $this->initTime;
|
||||
echo"============================================================================\n";
|
||||
echo " PROFILER OUTPUT\n";
|
||||
echo"============================================================================\n";
|
||||
print( "Calls Time Routine\n");
|
||||
echo"-----------------------------------------------------------------------------\n";
|
||||
while (list ($key, $val) = each ($this->description)) {
|
||||
$t = $this->elapsedTime($key);
|
||||
$total = $this->running[$key];
|
||||
$count = $this->count[$key];
|
||||
$TimedTotal += $total;
|
||||
$perc = ($total/$oaTime)*100;
|
||||
$tot_perc+=$perc;
|
||||
// $perc=sprintf("%3.2f", $perc );
|
||||
$lines[ sprintf( "%3d %3.4f ms (%3.2f %%) %s\n", $count, $total*1000, $perc, $key) ] = $total;
|
||||
}
|
||||
arsort($lines);
|
||||
foreach($lines as $line => $total) {
|
||||
echo $line;
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
echo "\n";
|
||||
|
||||
$missed=$oaTime-$TimedTotal;
|
||||
$perc = ($missed/$oaTime)*100;
|
||||
$tot_perc+=$perc;
|
||||
// $perc=sprintf("%3.2f", $perc );
|
||||
printf( " %3.4f ms (%3.2f %%) %s\n", $missed*1000,$perc, "Missed");
|
||||
$missed=$oaTime-$TimedTotal;
|
||||
$perc = ($missed/$oaTime)*100;
|
||||
$tot_perc+=$perc;
|
||||
// $perc=sprintf("%3.2f", $perc );
|
||||
printf( " %3.4f ms (%3.2f %%) %s\n", $missed*1000,$perc, "Missed");
|
||||
|
||||
echo"============================================================================\n";
|
||||
echo"============================================================================\n";
|
||||
|
||||
printf( " %3.4f ms (%3.2f %%) %s\n", $oaTime*1000,$tot_perc, "OVERALL TIME");
|
||||
printf( " %3.4f ms (%3.2f %%) %s\n", $oaTime*1000,$tot_perc, "OVERALL TIME");
|
||||
|
||||
echo"============================================================================\n";
|
||||
echo"============================================================================\n";
|
||||
|
||||
print("</pre>");
|
||||
}
|
||||
}
|
||||
print("</pre>");
|
||||
}
|
||||
}
|
||||
|
||||
public function printTrace( $enabled=false )
|
||||
{
|
||||
if($this->trace_enabled||$enabled){
|
||||
print("<pre>");
|
||||
print("Trace\n$this->trace\n\n");
|
||||
print("</pre>");
|
||||
}
|
||||
}
|
||||
public function printTrace( $enabled=false )
|
||||
{
|
||||
if($this->trace_enabled||$enabled){
|
||||
print("<pre>");
|
||||
print("Trace\n$this->trace\n\n");
|
||||
print("</pre>");
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal Use Only Functions
|
||||
/// Internal Use Only Functions
|
||||
|
||||
/**
|
||||
* Get the current time as accuratly as possible
|
||||
*
|
||||
*/
|
||||
public function getMicroTime(){
|
||||
$tmp=explode(' ', microtime());
|
||||
$rt=$tmp[0]+$tmp[1];
|
||||
return $rt;
|
||||
}
|
||||
/**
|
||||
* Get the current time as accuratly as possible
|
||||
*
|
||||
*/
|
||||
public function getMicroTime(){
|
||||
$tmp=explode(' ', microtime());
|
||||
$rt=$tmp[0]+$tmp[1];
|
||||
return $rt;
|
||||
}
|
||||
|
||||
/**
|
||||
* resume an individual timer
|
||||
*
|
||||
*/
|
||||
public function __resumeTimer($name){
|
||||
$this->trace.="resume $name\n";
|
||||
$this->startTime[$name] = $this->getMicroTime();
|
||||
}
|
||||
/**
|
||||
* resume an individual timer
|
||||
*
|
||||
*/
|
||||
public function __resumeTimer($name){
|
||||
$this->trace.="resume $name\n";
|
||||
$this->startTime[$name] = $this->getMicroTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* suspend an individual timer
|
||||
*
|
||||
*/
|
||||
public function __suspendTimer($name){
|
||||
$this->trace.="suspend $name\n";
|
||||
$this->endTime[$name] = $this->getMicroTime();
|
||||
if (!array_key_exists($name, $this->running))
|
||||
$this->running[$name] = $this->elapsedTime($name);
|
||||
else
|
||||
$this->running[$name] += $this->elapsedTime($name);
|
||||
}
|
||||
/**
|
||||
* suspend an individual timer
|
||||
*
|
||||
*/
|
||||
public function __suspendTimer($name){
|
||||
$this->trace.="suspend $name\n";
|
||||
$this->endTime[$name] = $this->getMicroTime();
|
||||
if (!array_key_exists($name, $this->running))
|
||||
$this->running[$name] = $this->elapsedTime($name);
|
||||
else
|
||||
$this->running[$name] += $this->elapsedTime($name);
|
||||
}
|
||||
}
|
||||
|
@ -83,17 +83,17 @@ class SapphireTestReporter implements PHPUnit_Framework_TestListener {
|
||||
public function __construct() {
|
||||
@include_once 'Benchmark/Timer.php';
|
||||
if(class_exists('Benchmark_Timer')) {
|
||||
$this->timer = new Benchmark_Timer();
|
||||
$this->hasTimer = true;
|
||||
$this->timer = new Benchmark_Timer();
|
||||
$this->hasTimer = true;
|
||||
} else {
|
||||
$this->hasTimer = false;
|
||||
$this->hasTimer = false;
|
||||
}
|
||||
|
||||
$this->suiteResults = array(
|
||||
'suites' => array(), // array of suites run
|
||||
'hasTimer' => $this->hasTimer, // availability of PEAR Benchmark_Timer
|
||||
'totalTests' => 0 // total number of tests run
|
||||
);
|
||||
$this->suiteResults = array(
|
||||
'suites' => array(), // array of suites run
|
||||
'hasTimer' => $this->hasTimer, // availability of PEAR Benchmark_Timer
|
||||
'totalTests' => 0 // total number of tests run
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,14 +117,14 @@ class SapphireTestReporter implements PHPUnit_Framework_TestListener {
|
||||
public function startTestSuite( PHPUnit_Framework_TestSuite $suite) {
|
||||
if(strlen($suite->getName())) {
|
||||
$this->endCurrentTestSuite();
|
||||
$this->currentSuite = array(
|
||||
'suite' => $suite, // the test suite
|
||||
'tests' => array(), // the tests in the suite
|
||||
'errors' => 0, // number of tests with errors (including setup errors)
|
||||
'failures' => 0, // number of tests which failed
|
||||
'incomplete' => 0, // number of tests that were not completed correctly
|
||||
$this->currentSuite = array(
|
||||
'suite' => $suite, // the test suite
|
||||
'tests' => array(), // the tests in the suite
|
||||
'errors' => 0, // number of tests with errors (including setup errors)
|
||||
'failures' => 0, // number of tests which failed
|
||||
'incomplete' => 0, // number of tests that were not completed correctly
|
||||
'error' => null); // Any error encountered during setup of the test suite
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,7 +226,7 @@ class SapphireTestReporter implements PHPUnit_Framework_TestListener {
|
||||
$this->currentSuite['incomplete']++;
|
||||
$this->addStatus(TEST_INCOMPLETE, $e->toString(), $this->getTestException($test, $e), $e->getTrace());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not used
|
||||
*
|
||||
@ -257,7 +257,7 @@ class SapphireTestReporter implements PHPUnit_Framework_TestListener {
|
||||
$this->currentTest = null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Upon completion of a test, records the execution time (if available) and adds the test to
|
||||
* the tests performed in the current suite.
|
||||
*
|
||||
|
@ -27,13 +27,13 @@ class SilverStripeListener implements PHPUnit_Framework_TestListener {
|
||||
|
||||
public function startTest(PHPUnit_Framework_Test $test) {
|
||||
}
|
||||
|
||||
|
||||
public function endTest(PHPUnit_Framework_Test $test, $time) {
|
||||
}
|
||||
|
||||
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {
|
||||
}
|
||||
|
||||
|
||||
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ class TeamCityListener implements PHPUnit_Framework_TestListener {
|
||||
$class = get_class($test);
|
||||
echo "##teamcity[testStarted name='{$class}.{$test->getName()}']\n";
|
||||
}
|
||||
|
||||
|
||||
public function endTest(PHPUnit_Framework_Test $test, $time) {
|
||||
$class = get_class($test);
|
||||
echo "##teamcity[testFinished name='{$class}.{$test->getName()}' duration='$time']\n";
|
||||
@ -40,7 +40,7 @@ class TeamCityListener implements PHPUnit_Framework_TestListener {
|
||||
echo "##teamcity[testFailed type='exception' name='{$class}.{$test->getName()}' message='$message'"
|
||||
. " details='$trace']\n";
|
||||
}
|
||||
|
||||
|
||||
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {
|
||||
$class = get_class($test);
|
||||
$message = $this->escape($e->getMessage());
|
||||
|
@ -13,15 +13,15 @@ class SS_TestListener implements PHPUnit_Framework_TestListener {
|
||||
|
||||
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {}
|
||||
|
||||
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {}
|
||||
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {}
|
||||
|
||||
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
|
||||
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
|
||||
|
||||
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
|
||||
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
|
||||
|
||||
public function startTest(PHPUnit_Framework_Test $test) {}
|
||||
public function startTest(PHPUnit_Framework_Test $test) {}
|
||||
|
||||
public function endTest(PHPUnit_Framework_Test $test, $time) {}
|
||||
public function endTest(PHPUnit_Framework_Test $test, $time) {}
|
||||
|
||||
public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {
|
||||
$name = $suite->getName();
|
||||
@ -29,7 +29,7 @@ class SS_TestListener implements PHPUnit_Framework_TestListener {
|
||||
|
||||
$this->class = new $name();
|
||||
$this->class->setUpOnce();
|
||||
}
|
||||
}
|
||||
|
||||
public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {
|
||||
$name = $suite->getName();
|
||||
|
@ -138,14 +138,14 @@ class PhpUnitWrapper implements IPhpUnitWrapper {
|
||||
public static function inst() {
|
||||
|
||||
if (self::$phpunit_wrapper == null) {
|
||||
if (fileExistsInIncludePath("/PHPUnit/Autoload.php")) {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper_3_5();
|
||||
} else
|
||||
if (fileExistsInIncludePath("/PHPUnit/Framework.php")) {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper_3_4();
|
||||
} else {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper();
|
||||
}
|
||||
if (fileExistsInIncludePath("/PHPUnit/Autoload.php")) {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper_3_5();
|
||||
} else
|
||||
if (fileExistsInIncludePath("/PHPUnit/Framework.php")) {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper_3_4();
|
||||
} else {
|
||||
self::$phpunit_wrapper = new PhpUnitWrapper();
|
||||
}
|
||||
self::$phpunit_wrapper->init();
|
||||
|
||||
}
|
||||
|
@ -35,11 +35,11 @@ class PhpUnitWrapper_3_5 extends PhpUnitWrapper {
|
||||
protected function beforeRunTests() {
|
||||
|
||||
if($this->getCoverageStatus()) {
|
||||
$this->coverage = new PHP_CodeCoverage();
|
||||
$this->coverage = new PHP_CodeCoverage();
|
||||
$coverage = $this->coverage;
|
||||
|
||||
$filter = $coverage->filter();
|
||||
$modules = $this->moduleDirectories();
|
||||
$filter = $coverage->filter();
|
||||
$modules = $this->moduleDirectories();
|
||||
|
||||
foreach(TestRunner::$coverage_filter_dirs as $dir) {
|
||||
if($dir[0] == '*') {
|
||||
|
@ -363,12 +363,12 @@ class Email extends ViewableData {
|
||||
* Validates the email address. Returns true of false
|
||||
*/
|
||||
public static function validEmailAddress($address) {
|
||||
if (function_exists('filter_var')) {
|
||||
return filter_var($address, FILTER_VALIDATE_EMAIL);
|
||||
} else {
|
||||
return preg_match('#^([a-zA-Z0-9_+\.\-]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)'
|
||||
. '|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$#', $address);
|
||||
}
|
||||
if (function_exists('filter_var')) {
|
||||
return filter_var($address, FILTER_VALIDATE_EMAIL);
|
||||
} else {
|
||||
return preg_match('#^([a-zA-Z0-9_+\.\-]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)'
|
||||
. '|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$#', $address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,9 +120,9 @@ class Mailer {
|
||||
dieprintr($customheaders);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$bodyIsUnicode = (strpos($htmlContent,"&#") !== false);
|
||||
$plainEncoding = "";
|
||||
$plainEncoding = "";
|
||||
|
||||
// We generate plaintext content by default, but you can pass custom stuff
|
||||
$plainEncoding = '';
|
||||
@ -146,7 +146,7 @@ class Mailer {
|
||||
|
||||
// Make the HTML part
|
||||
$headers["Content-Type"] = "text/html; charset=utf-8";
|
||||
|
||||
|
||||
|
||||
// Add basic wrapper tags if the body tag hasn't been given
|
||||
if(stripos($htmlContent, '<body') === false) {
|
||||
@ -199,14 +199,14 @@ class Mailer {
|
||||
$headers["From"] = $this->validEmailAddr($from);
|
||||
|
||||
// Messages with the X-SilverStripeMessageID header can be tracked
|
||||
if(isset($customheaders["X-SilverStripeMessageID"]) && defined('BOUNCE_EMAIL')) {
|
||||
$bounceAddress = BOUNCE_EMAIL;
|
||||
} else {
|
||||
$bounceAddress = $from;
|
||||
}
|
||||
if(isset($customheaders["X-SilverStripeMessageID"]) && defined('BOUNCE_EMAIL')) {
|
||||
$bounceAddress = BOUNCE_EMAIL;
|
||||
} else {
|
||||
$bounceAddress = $from;
|
||||
}
|
||||
|
||||
// Strip the human name from the bounce address
|
||||
if(preg_match('/^([^<>]*)<([^<>]+)> *$/', $bounceAddress, $parts)) $bounceAddress = $parts[2];
|
||||
// Strip the human name from the bounce address
|
||||
if(preg_match('/^([^<>]*)<([^<>]+)> *$/', $bounceAddress, $parts)) $bounceAddress = $parts[2];
|
||||
|
||||
// $headers["Sender"] = $from;
|
||||
$headers["X-Mailer"] = X_MAILER;
|
||||
@ -350,9 +350,9 @@ class Mailer {
|
||||
$file['contents'] = $this->QuotedPrintable_encode($file['contents']);
|
||||
}
|
||||
|
||||
$headers = "Content-type: $mimeType;\n\tname=\"$base\"\n".
|
||||
"Content-Transfer-Encoding: $encoding\n".
|
||||
"Content-Disposition: $disposition;\n\tfilename=\"$base\"\n" ;
|
||||
$headers = "Content-type: $mimeType;\n\tname=\"$base\"\n".
|
||||
"Content-Transfer-Encoding: $encoding\n".
|
||||
"Content-Disposition: $disposition;\n\tfilename=\"$base\"\n" ;
|
||||
|
||||
if ( isset($file['contentLocation']) ) $headers .= 'Content-Location: ' . $file['contentLocation'] . "\n" ;
|
||||
|
||||
@ -487,4 +487,4 @@ function validEmailAddr($emailAddress) {
|
||||
|
||||
$mailer = Injector::inst()->create('Mailer');
|
||||
return $mailer->validEmailAddr($emailAddress);
|
||||
}
|
||||
}
|
||||
|
@ -135,9 +135,9 @@ class GDBackend extends Object implements Image_Backend {
|
||||
* @todo This method isn't very efficent
|
||||
*/
|
||||
public function fittedResize($width, $height) {
|
||||
$gd = $this->resizeByHeight($height);
|
||||
if($gd->width > $width) $gd = $gd->resizeByWidth($width);
|
||||
return $gd;
|
||||
$gd = $this->resizeByHeight($height);
|
||||
if($gd->width > $width) $gd = $gd->resizeByWidth($width);
|
||||
return $gd;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,9 +199,9 @@ class GDBackend extends Object implements Image_Backend {
|
||||
if(!$this->gd) return;
|
||||
|
||||
if(function_exists("imagerotate")) {
|
||||
$newGD = imagerotate($this->gd, $angle,0);
|
||||
$newGD = imagerotate($this->gd, $angle,0);
|
||||
} else {
|
||||
//imagerotate is not included in PHP included in Ubuntu
|
||||
//imagerotate is not included in PHP included in Ubuntu
|
||||
$newGD = $this->rotatePixelByPixel($angle);
|
||||
}
|
||||
$output = clone $this;
|
||||
@ -210,45 +210,45 @@ class GDBackend extends Object implements Image_Backend {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates image by given angle. It's slow because makes it pixel by pixel rather than
|
||||
* using built-in function. Used when imagerotate function is not available(i.e. Ubuntu)
|
||||
*
|
||||
* @param angle
|
||||
*
|
||||
* @return GD
|
||||
*/
|
||||
* Rotates image by given angle. It's slow because makes it pixel by pixel rather than
|
||||
* using built-in function. Used when imagerotate function is not available(i.e. Ubuntu)
|
||||
*
|
||||
* @param angle
|
||||
*
|
||||
* @return GD
|
||||
*/
|
||||
|
||||
public function rotatePixelByPixel($angle) {
|
||||
$sourceWidth = imagesx($this->gd);
|
||||
$sourceHeight = imagesy($this->gd);
|
||||
if ($angle == 180) {
|
||||
$destWidth = $sourceWidth;
|
||||
$destHeight = $sourceHeight;
|
||||
} else {
|
||||
$destWidth = $sourceHeight;
|
||||
$destHeight = $sourceWidth;
|
||||
}
|
||||
$rotate=imagecreatetruecolor($destWidth,$destHeight);
|
||||
imagealphablending($rotate, false);
|
||||
for ($x = 0; $x < ($sourceWidth); $x++) {
|
||||
for ($y = 0; $y < ($sourceHeight); $y++) {
|
||||
$color = imagecolorat($this->gd, $x, $y);
|
||||
switch ($angle) {
|
||||
case 90:
|
||||
imagesetpixel($rotate, $y, $destHeight - $x - 1, $color);
|
||||
break;
|
||||
case 180:
|
||||
imagesetpixel($rotate, $destWidth - $x - 1, $destHeight - $y - 1, $color);
|
||||
break;
|
||||
case 270:
|
||||
imagesetpixel($rotate, $destWidth - $y - 1, $x, $color);
|
||||
break;
|
||||
default: $rotate = $this->gd;
|
||||
};
|
||||
}
|
||||
}
|
||||
return $rotate;
|
||||
}
|
||||
public function rotatePixelByPixel($angle) {
|
||||
$sourceWidth = imagesx($this->gd);
|
||||
$sourceHeight = imagesy($this->gd);
|
||||
if ($angle == 180) {
|
||||
$destWidth = $sourceWidth;
|
||||
$destHeight = $sourceHeight;
|
||||
} else {
|
||||
$destWidth = $sourceHeight;
|
||||
$destHeight = $sourceWidth;
|
||||
}
|
||||
$rotate=imagecreatetruecolor($destWidth,$destHeight);
|
||||
imagealphablending($rotate, false);
|
||||
for ($x = 0; $x < ($sourceWidth); $x++) {
|
||||
for ($y = 0; $y < ($sourceHeight); $y++) {
|
||||
$color = imagecolorat($this->gd, $x, $y);
|
||||
switch ($angle) {
|
||||
case 90:
|
||||
imagesetpixel($rotate, $y, $destHeight - $x - 1, $color);
|
||||
break;
|
||||
case 180:
|
||||
imagesetpixel($rotate, $destWidth - $x - 1, $destHeight - $y - 1, $color);
|
||||
break;
|
||||
case 270:
|
||||
imagesetpixel($rotate, $destWidth - $y - 1, $x, $color);
|
||||
break;
|
||||
default: $rotate = $this->gd;
|
||||
};
|
||||
}
|
||||
}
|
||||
return $rotate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -271,7 +271,7 @@ class GDBackend extends Object implements Image_Backend {
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Method return width of image.
|
||||
*
|
||||
* @return integer width.
|
||||
@ -334,9 +334,9 @@ class GDBackend extends Object implements Image_Backend {
|
||||
/**
|
||||
* Resize to fit fully within the given box, without resizing. Extra space left around
|
||||
* the image will be padded with the background color.
|
||||
* @param width
|
||||
* @param height
|
||||
* @param backgroundColour
|
||||
* @param width
|
||||
* @param height
|
||||
* @param backgroundColour
|
||||
*/
|
||||
public function paddedResize($width, $height, $backgroundColor = "FFFFFF") {
|
||||
if(!$this->gd) return;
|
||||
@ -476,4 +476,4 @@ class GD extends GDBackend {
|
||||
);
|
||||
GDBackend::set_default_quality($quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class AjaxUniqueTextField extends TextField {
|
||||
|
||||
parent::__construct($name, $title, $value);
|
||||
}
|
||||
|
||||
|
||||
public function Field($properties = array()) {
|
||||
$url = Convert::raw2att( $this->validateURL );
|
||||
|
||||
|
@ -79,7 +79,7 @@ class CheckboxSetField extends OptionsetField {
|
||||
if(is_a($object, 'DataObject')) {
|
||||
$items[] = $object->ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif($values && is_string($values)) {
|
||||
$items = explode(',', $values);
|
||||
$items = str_replace('{comma}', ',', $items);
|
||||
|
@ -163,8 +163,8 @@ class CompositeField extends FormField {
|
||||
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
|
||||
if(isset($list[$name])) {
|
||||
user_error("collateDataFields() I noticed that a field called '$name' appears twice in"
|
||||
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
|
||||
. " '{$list[$name]->class}'", E_USER_ERROR);
|
||||
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
|
||||
. " '{$list[$name]->class}'", E_USER_ERROR);
|
||||
}
|
||||
$list[$name] = $field;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class CreditCardField extends TextField {
|
||||
if($this->value) foreach($this->value as $part){
|
||||
if(!$part || !(strlen($part) == 4) || !preg_match("/([0-9]{4})/", $part)){
|
||||
switch($i){
|
||||
case 0: $number = _t('CreditCardField.FIRST', 'first'); break;
|
||||
case 0: $number = _t('CreditCardField.FIRST', 'first'); break;
|
||||
case 1: $number = _t('CreditCardField.SECOND', 'second'); break;
|
||||
case 2: $number = _t('CreditCardField.THIRD', 'third'); break;
|
||||
case 3: $number = _t('CreditCardField.FOURTH', 'fourth'); break;
|
||||
|
@ -43,9 +43,9 @@ require_once 'Zend/Date.php';
|
||||
*
|
||||
* ## Example: German dates with separate fields for day, month, year
|
||||
*
|
||||
* $f = new DateField('MyDate');
|
||||
* $f->setLocale('de_DE');
|
||||
* $f->setConfig('dmyfields');
|
||||
* $f = new DateField('MyDate');
|
||||
* $f->setLocale('de_DE');
|
||||
* $f->setConfig('dmyfields');
|
||||
*
|
||||
* # Validation
|
||||
*
|
||||
@ -314,11 +314,11 @@ class DateField extends TextField {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set_default_config($k, $v) {
|
||||
if (array_key_exists($k,self::$default_config)) {
|
||||
self::$default_config[$k]=$v;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (array_key_exists($k,self::$default_config)) {
|
||||
self::$default_config[$k]=$v;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -567,7 +567,7 @@ class DateField_View_JQuery extends Object {
|
||||
// Include language files (if required)
|
||||
if ($this->jqueryLocaleFile){
|
||||
Requirements::javascript($this->jqueryLocaleFile);
|
||||
}
|
||||
}
|
||||
|
||||
Requirements::javascript(FRAMEWORK_DIR . "/javascript/DateField.js");
|
||||
}
|
||||
@ -609,51 +609,51 @@ class DateField_View_JQuery extends Object {
|
||||
public static function convert_iso_to_jquery_format($format) {
|
||||
$convert = array(
|
||||
'/([^d])d([^d])/' => '$1d$2',
|
||||
'/^d([^d])/' => 'd$1',
|
||||
'/([^d])d$/' => '$1d',
|
||||
'/dd/' => 'dd',
|
||||
'/SS/' => '',
|
||||
'/eee/' => 'd',
|
||||
'/e/' => 'N',
|
||||
'/D/' => '',
|
||||
'/EEEE/' => 'DD',
|
||||
'/EEE/' => 'D',
|
||||
'/w/' => '',
|
||||
'/^d([^d])/' => 'd$1',
|
||||
'/([^d])d$/' => '$1d',
|
||||
'/dd/' => 'dd',
|
||||
'/SS/' => '',
|
||||
'/eee/' => 'd',
|
||||
'/e/' => 'N',
|
||||
'/D/' => '',
|
||||
'/EEEE/' => 'DD',
|
||||
'/EEE/' => 'D',
|
||||
'/w/' => '',
|
||||
// make single "M" lowercase
|
||||
'/([^M])M([^M])/' => '$1m$2',
|
||||
'/([^M])M([^M])/' => '$1m$2',
|
||||
// make single "M" at start of line lowercase
|
||||
'/^M([^M])/' => 'm$1',
|
||||
'/^M([^M])/' => 'm$1',
|
||||
// make single "M" at end of line lowercase
|
||||
'/([^M])M$/' => '$1m',
|
||||
'/([^M])M$/' => '$1m',
|
||||
// match exactly three capital Ms not preceeded or followed by an M
|
||||
'/(?<!M)MMM(?!M)/' => 'M',
|
||||
'/(?<!M)MMM(?!M)/' => 'M',
|
||||
// match exactly two capital Ms not preceeded or followed by an M
|
||||
'/(?<!M)MM(?!M)/' => 'mm',
|
||||
'/(?<!M)MM(?!M)/' => 'mm',
|
||||
// match four capital Ms (maximum allowed)
|
||||
'/MMMM/' => 'MM',
|
||||
'/l/' => '',
|
||||
'/YYYY/' => 'yy',
|
||||
'/yyyy/' => 'yy',
|
||||
// See http://open.silverstripe.org/ticket/7669
|
||||
'/y{1,3}/' => 'yy',
|
||||
'/a/' => '',
|
||||
'/B/' => '',
|
||||
'/hh/' => '',
|
||||
'/h/' => '',
|
||||
'/([^H])H([^H])/' => '',
|
||||
'/^H([^H])/' => '',
|
||||
'/([^H])H$/' => '',
|
||||
'/HH/' => '',
|
||||
// '/mm/' => '',
|
||||
'/ss/' => '',
|
||||
'/zzzz/' => '',
|
||||
'/I/' => '',
|
||||
'/ZZZZ/' => '',
|
||||
'/Z/' => '',
|
||||
'/z/' => '',
|
||||
'/X/' => '',
|
||||
'/r/' => '',
|
||||
'/U/' => '',
|
||||
'/MMMM/' => 'MM',
|
||||
'/l/' => '',
|
||||
'/YYYY/' => 'yy',
|
||||
'/yyyy/' => 'yy',
|
||||
// See http://open.silverstripe.org/ticket/7669
|
||||
'/y{1,3}/' => 'yy',
|
||||
'/a/' => '',
|
||||
'/B/' => '',
|
||||
'/hh/' => '',
|
||||
'/h/' => '',
|
||||
'/([^H])H([^H])/' => '',
|
||||
'/^H([^H])/' => '',
|
||||
'/([^H])H$/' => '',
|
||||
'/HH/' => '',
|
||||
// '/mm/' => '',
|
||||
'/ss/' => '',
|
||||
'/zzzz/' => '',
|
||||
'/I/' => '',
|
||||
'/ZZZZ/' => '',
|
||||
'/Z/' => '',
|
||||
'/z/' => '',
|
||||
'/X/' => '',
|
||||
'/r/' => '',
|
||||
'/U/' => '',
|
||||
);
|
||||
$patterns = array_keys($convert);
|
||||
$replacements = array_values($convert);
|
||||
|
@ -90,12 +90,12 @@ class FieldGroup extends CompositeField {
|
||||
*
|
||||
* @param string $zebra one of odd or even.
|
||||
*/
|
||||
public function setZebra($zebra) {
|
||||
if($zebra == 'odd' || $zebra == 'even') $this->zebra = $zebra;
|
||||
else user_error("setZebra passed '$zebra'. It should be passed 'odd' or 'even'", E_USER_WARNING);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setZebra($zebra) {
|
||||
if($zebra == 'odd' || $zebra == 'even') $this->zebra = $zebra;
|
||||
else user_error("setZebra passed '$zebra'. It should be passed 'odd' or 'even'", E_USER_WARNING);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -132,4 +132,4 @@ class FieldGroup extends CompositeField {
|
||||
public function php($data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -999,7 +999,7 @@ class Form extends RequestHandler {
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate(){
|
||||
public function validate(){
|
||||
if($this->validator){
|
||||
$errors = $this->validator->validate();
|
||||
|
||||
@ -1420,7 +1420,7 @@ class Form extends RequestHandler {
|
||||
$result .= "</ul>";
|
||||
|
||||
if( $this->validator )
|
||||
$result .= '<h3>'._t('Form.VALIDATOR', 'Validator').'</h3>' . $this->validator->debug();
|
||||
$result .= '<h3>'._t('Form.VALIDATOR', 'Validator').'</h3>' . $this->validator->debug();
|
||||
|
||||
return $result;
|
||||
}
|
||||
@ -1437,8 +1437,8 @@ class Form extends RequestHandler {
|
||||
*/
|
||||
public function testSubmission($action, $data) {
|
||||
$data['action_' . $action] = true;
|
||||
|
||||
return Director::test($this->FormAction(), $data, Controller::curr()->getSession());
|
||||
|
||||
return Director::test($this->FormAction(), $data, Controller::curr()->getSession());
|
||||
|
||||
//$response = $this->controller->run($data);
|
||||
//return $response;
|
||||
|
@ -85,7 +85,7 @@ class FormField extends RequestHandler {
|
||||
protected
|
||||
$template,
|
||||
$fieldHolderTemplate,
|
||||
$smallFieldHolderTemplate;
|
||||
$smallFieldHolderTemplate;
|
||||
|
||||
/**
|
||||
* @var array All attributes on the form field (not the field holder).
|
||||
@ -582,14 +582,14 @@ class FormField extends RequestHandler {
|
||||
return $obj->renderWith($this->getFieldHolderTemplates());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a restricted field holder used within things like FieldGroups.
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function SmallFieldHolder($properties = array()) {
|
||||
/**
|
||||
* Returns a restricted field holder used within things like FieldGroups.
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function SmallFieldHolder($properties = array()) {
|
||||
$obj = ($properties) ? $this->customise($properties) : $this;
|
||||
|
||||
return $obj->renderWith($this->getSmallFieldHolderTemplates());
|
||||
|
@ -175,8 +175,8 @@ class HtmlEditorField extends TextareaField {
|
||||
// Save file & link tracking data.
|
||||
if(class_exists('SiteTree')) {
|
||||
if($record->ID && $record->many_many('LinkTracking') && $tracker = $record->LinkTracking()) {
|
||||
$tracker->removeByFilter(sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d',
|
||||
$this->name, $record->ID));
|
||||
$tracker->removeByFilter(sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d',
|
||||
$this->name, $record->ID));
|
||||
|
||||
if($linkedPages) foreach($linkedPages as $item) {
|
||||
$SQL_fieldName = Convert::raw2sql($this->name);
|
||||
@ -186,9 +186,9 @@ class HtmlEditorField extends TextareaField {
|
||||
}
|
||||
|
||||
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
|
||||
$tracker->where(
|
||||
sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d', $this->name, $record->ID)
|
||||
)->removeAll();
|
||||
$tracker->where(
|
||||
sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d', $this->name, $record->ID)
|
||||
)->removeAll();
|
||||
|
||||
$fieldName = $this->name;
|
||||
if($linkedFiles) foreach($linkedFiles as $item) {
|
||||
|
@ -14,8 +14,8 @@ class NumericField extends TextField{
|
||||
/** PHP Validation **/
|
||||
public function validate($validator){
|
||||
if($this->value && !is_numeric(trim($this->value))){
|
||||
$validator->validationError(
|
||||
$this->name,
|
||||
$validator->validationError(
|
||||
$this->name,
|
||||
_t(
|
||||
'NumericField.VALIDATION', "'{value}' is not a number, only numbers can be accepted for this field",
|
||||
array('value' => $this->value)
|
||||
|
@ -33,11 +33,11 @@ class PhoneNumberField extends FormField {
|
||||
list($countryCode, $areaCode, $phoneNumber, $extension) = $this->parseValue();
|
||||
$hasTitle = false;
|
||||
|
||||
if ($this->value=="") {
|
||||
$countryCode=$this->countryCode;
|
||||
$areaCode=$this->areaCode;
|
||||
$extension=$this->ext;
|
||||
}
|
||||
if ($this->value=="") {
|
||||
$countryCode=$this->countryCode;
|
||||
$areaCode=$this->areaCode;
|
||||
$extension=$this->ext;
|
||||
}
|
||||
|
||||
if($this->countryCode !== null) {
|
||||
$fields->push(new NumericField($this->name.'[Country]', '+', $countryCode, 4));
|
||||
@ -94,7 +94,7 @@ class PhoneNumberField extends FormField {
|
||||
preg_match( '/^(?:(?:\+(\d+))?\s*\((\d+)\))?\s*([0-9A-Za-z]*)\s*(?:[#]\s*(\d+))?$/', $this->value, $parts);
|
||||
else
|
||||
return array( '', '', $this->value, '' );
|
||||
|
||||
|
||||
if(is_array($parts)) array_shift( $parts );
|
||||
|
||||
for ($x=0;$x<=3;$x++) {
|
||||
|
@ -42,15 +42,15 @@ class RequiredFields extends Validator {
|
||||
* Debug helper
|
||||
*/
|
||||
public function debug() {
|
||||
if(!is_array($this->required)) return false;
|
||||
if(!is_array($this->required)) return false;
|
||||
|
||||
$result = "<ul>";
|
||||
foreach( $this->required as $name ){
|
||||
$result .= "<li>$name</li>";
|
||||
}
|
||||
$result = "<ul>";
|
||||
foreach( $this->required as $name ){
|
||||
$result .= "<li>$name</li>";
|
||||
}
|
||||
|
||||
$result .= "</ul>";
|
||||
return $result;
|
||||
$result .= "</ul>";
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,7 +211,7 @@ class GridField extends FormField {
|
||||
public function getManipulatedList() {
|
||||
$list = $this->getList();
|
||||
foreach($this->getComponents() as $item) {
|
||||
if($item instanceof GridField_DataManipulator) {
|
||||
if($item instanceof GridField_DataManipulator) {
|
||||
$list = $item->getManipulatedData($this, $list);
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +244,6 @@
|
||||
this._super();
|
||||
this.selectable('destroy');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -6,15 +6,15 @@
|
||||
* ajax / iframe submissions
|
||||
*/
|
||||
|
||||
var ss = ss || {};
|
||||
var ss = ss || {};
|
||||
/**
|
||||
* Wrapper for HTML WYSIWYG libraries, which abstracts library internals
|
||||
* from interface concerns like inserting and editing links.
|
||||
* Caution: Incomplete and unstable API.
|
||||
*/
|
||||
ss.editorWrappers = {};
|
||||
ss.editorWrappers.initial
|
||||
ss.editorWrappers.tinyMCE = (function() {
|
||||
ss.editorWrappers = {};
|
||||
ss.editorWrappers.initial
|
||||
ss.editorWrappers.tinyMCE = (function() {
|
||||
return {
|
||||
init: function(config) {
|
||||
if(!ss.editorWrappers.tinyMCE.initialized) {
|
||||
@ -807,7 +807,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
|
||||
if(header) header[(hasItems) ? 'show' : 'hide']();
|
||||
|
||||
// Disable "insert" button if no files are selected
|
||||
this.find('.Actions :submit')
|
||||
this.find('.Actions :submit')
|
||||
.button(hasItems ? 'enable' : 'disable')
|
||||
.toggleClass('ui-state-disabled', !hasItems);
|
||||
|
||||
|
@ -108,7 +108,7 @@ ss.i18n = {
|
||||
* @return string result : Stripped string
|
||||
*
|
||||
*/
|
||||
stripStr: function(str) {
|
||||
stripStr: function(str) {
|
||||
return str.replace(/^\s*/, "").replace(/\s*$/, "");
|
||||
},
|
||||
|
||||
@ -228,4 +228,4 @@ ss.i18n = {
|
||||
|
||||
ss.i18n.addEvent(window, "load", function() {
|
||||
ss.i18n.init();
|
||||
});
|
||||
});
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
// loaded files list - to protect against loading existed file again (by PGA)
|
||||
_ondemand_loaded_list : null,
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given CSS or JS script has already been loaded
|
||||
*/
|
||||
@ -160,4 +160,4 @@
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
})(jQuery);
|
||||
|
@ -212,7 +212,7 @@ Tree.prototype = {
|
||||
}
|
||||
|
||||
// Update the helper classes accordingly
|
||||
if(!hasChildren) this.removeNodeClass('children');
|
||||
if(!hasChildren) this.removeNodeClass('children');
|
||||
else this.lastTreeNode().addNodeClass('last');
|
||||
|
||||
// Update the helper variables
|
||||
@ -303,8 +303,8 @@ TreeNode.prototype = {
|
||||
|
||||
// Move all the nodes up until that point into spanC
|
||||
for(j=startingPoint;j<stoppingPoint;j++) {
|
||||
/* Use [startingPoint] every time, because the appentChild
|
||||
removes the node, so it then points to the next one. */
|
||||
/* Use [startingPoint] every time, because the appentChild
|
||||
removes the node, so it then points to the next one. */
|
||||
spanC.appendChild(li.childNodes[startingPoint]);
|
||||
}
|
||||
|
||||
@ -527,7 +527,7 @@ TreeNode.prototype = {
|
||||
}
|
||||
|
||||
// Update the helper classes accordingly
|
||||
if(!hasChildren) this.removeNodeClass('children');
|
||||
if(!hasChildren) this.removeNodeClass('children');
|
||||
else this.lastTreeNode().addNodeClass('last');
|
||||
|
||||
// Update the helper variables
|
||||
@ -599,27 +599,27 @@ TreeNode.prototype = {
|
||||
|
||||
/* Close or Open all the trees, at beginning or on request. sjd. */
|
||||
function treeCloseAll() {
|
||||
var candidates = document.getElementsByTagName('li');
|
||||
for (var i=0;i<candidates.length;i++) {
|
||||
var aSpan = candidates[i].childNodes[0];
|
||||
if(aSpan.childNodes[0] && aSpan.childNodes[0].className == "b") {
|
||||
if (!aSpan.className.match(/spanClosed/) && candidates[i].id != 'record-0' ) {
|
||||
aSpan.childNodes[0].onclick();
|
||||
}
|
||||
}
|
||||
}
|
||||
var candidates = document.getElementsByTagName('li');
|
||||
for (var i=0;i<candidates.length;i++) {
|
||||
var aSpan = candidates[i].childNodes[0];
|
||||
if(aSpan.childNodes[0] && aSpan.childNodes[0].className == "b") {
|
||||
if (!aSpan.className.match(/spanClosed/) && candidates[i].id != 'record-0' ) {
|
||||
aSpan.childNodes[0].onclick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function treeOpenAll() {
|
||||
var candidates = document.getElementsByTagName('li');
|
||||
for (var i=0;i<candidates.length;i++) {
|
||||
var aSpan = candidates[i].childNodes[0];
|
||||
if(aSpan.childNodes[0] && aSpan.childNodes[0].className == "b") {
|
||||
if (aSpan.className.match(/spanClosed/)) {
|
||||
aSpan.childNodes[0].onclick();
|
||||
}
|
||||
}
|
||||
}
|
||||
var candidates = document.getElementsByTagName('li');
|
||||
for (var i=0;i<candidates.length;i++) {
|
||||
var aSpan = candidates[i].childNodes[0];
|
||||
if(aSpan.childNodes[0] && aSpan.childNodes[0].className == "b") {
|
||||
if (aSpan.className.match(/spanClosed/)) {
|
||||
aSpan.childNodes[0].onclick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -922,4 +922,4 @@ MultiselectTree.prototype = {
|
||||
delete this.selectedNodes[idx];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return boolean
|
||||
*/
|
||||
public function canSortBy($fieldName) {
|
||||
return $this->dataQuery()->query()->canSortBy($fieldName);
|
||||
return $this->dataQuery()->query()->canSortBy($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -718,7 +718,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return mixed
|
||||
*/
|
||||
public function max($fieldName) {
|
||||
return $this->dataQuery->max($fieldName);
|
||||
return $this->dataQuery->max($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -728,7 +728,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return mixed
|
||||
*/
|
||||
public function min($fieldName) {
|
||||
return $this->dataQuery->min($fieldName);
|
||||
return $this->dataQuery->min($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -738,7 +738,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return mixed
|
||||
*/
|
||||
public function avg($fieldName) {
|
||||
return $this->dataQuery->avg($fieldName);
|
||||
return $this->dataQuery->avg($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -748,7 +748,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return mixed
|
||||
*/
|
||||
public function sum($fieldName) {
|
||||
return $this->dataQuery->sum($fieldName);
|
||||
return $this->dataQuery->sum($fieldName);
|
||||
}
|
||||
|
||||
|
||||
@ -878,7 +878,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
|
||||
// Index current data
|
||||
foreach($this->column() as $id) {
|
||||
$has[$id] = true;
|
||||
$has[$id] = true;
|
||||
}
|
||||
|
||||
// Keep track of items to delete
|
||||
@ -996,7 +996,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
*/
|
||||
public function newObject($initialFields = null) {
|
||||
$class = $this->dataClass;
|
||||
return Injector::inst()->create($class, $initialFields, false, $this->model);
|
||||
return Injector::inst()->create($class, $initialFields, false, $this->model);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1012,14 +1012,14 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from this DataList by ID
|
||||
/**
|
||||
* Remove an item from this DataList by ID
|
||||
*
|
||||
* @param int $itemID - The primary ID
|
||||
*/
|
||||
*/
|
||||
public function removeByID($itemID) {
|
||||
$item = $this->byID($itemID);
|
||||
if($item) return $item->delete();
|
||||
$item = $this->byID($itemID);
|
||||
if($item) return $item->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1091,7 +1091,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($key) {
|
||||
return ($this->limit(1,$key)->First() != null);
|
||||
return ($this->limit(1,$key)->First() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1101,7 +1101,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @return DataObject
|
||||
*/
|
||||
public function offsetGet($key) {
|
||||
return $this->limit(1, $key)->First();
|
||||
return $this->limit(1, $key)->First();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1111,7 +1111,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function offsetSet($key, $value) {
|
||||
user_error("Can't alter items in a DataList using array-access", E_USER_ERROR);
|
||||
user_error("Can't alter items in a DataList using array-access", E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1120,7 +1120,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* @param mixed $key
|
||||
*/
|
||||
public function offsetUnset($key) {
|
||||
user_error("Can't alter items in a DataList using array-access", E_USER_ERROR);
|
||||
user_error("Can't alter items in a DataList using array-access", E_USER_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,46 +13,46 @@
|
||||
*
|
||||
* <code>
|
||||
* class Article extends DataObject implements PermissionProvider {
|
||||
* static $api_access = true;
|
||||
*
|
||||
* function canView($member = false) {
|
||||
* return Permission::check('ARTICLE_VIEW');
|
||||
* }
|
||||
* function canEdit($member = false) {
|
||||
* return Permission::check('ARTICLE_EDIT');
|
||||
* }
|
||||
* function canDelete() {
|
||||
* return Permission::check('ARTICLE_DELETE');
|
||||
* }
|
||||
* function canCreate() {
|
||||
* return Permission::check('ARTICLE_CREATE');
|
||||
* }
|
||||
* function providePermissions() {
|
||||
* return array(
|
||||
* 'ARTICLE_VIEW' => 'Read an article object',
|
||||
* 'ARTICLE_EDIT' => 'Edit an article object',
|
||||
* 'ARTICLE_DELETE' => 'Delete an article object',
|
||||
* 'ARTICLE_CREATE' => 'Create an article object',
|
||||
* );
|
||||
* }
|
||||
* static $api_access = true;
|
||||
*
|
||||
* function canView($member = false) {
|
||||
* return Permission::check('ARTICLE_VIEW');
|
||||
* }
|
||||
* function canEdit($member = false) {
|
||||
* return Permission::check('ARTICLE_EDIT');
|
||||
* }
|
||||
* function canDelete() {
|
||||
* return Permission::check('ARTICLE_DELETE');
|
||||
* }
|
||||
* function canCreate() {
|
||||
* return Permission::check('ARTICLE_CREATE');
|
||||
* }
|
||||
* function providePermissions() {
|
||||
* return array(
|
||||
* 'ARTICLE_VIEW' => 'Read an article object',
|
||||
* 'ARTICLE_EDIT' => 'Edit an article object',
|
||||
* 'ARTICLE_DELETE' => 'Delete an article object',
|
||||
* 'ARTICLE_CREATE' => 'Create an article object',
|
||||
* );
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* Object-level access control by {@link Group} membership:
|
||||
* <code>
|
||||
* class Article extends DataObject {
|
||||
* static $api_access = true;
|
||||
*
|
||||
* function canView($member = false) {
|
||||
* if(!$member) $member = Member::currentUser();
|
||||
* return $member->inGroup('Subscribers');
|
||||
* }
|
||||
* function canEdit($member = false) {
|
||||
* if(!$member) $member = Member::currentUser();
|
||||
* return $member->inGroup('Editors');
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* static $api_access = true;
|
||||
*
|
||||
* function canView($member = false) {
|
||||
* if(!$member) $member = Member::currentUser();
|
||||
* return $member->inGroup('Subscribers');
|
||||
* }
|
||||
* function canEdit($member = false) {
|
||||
* if(!$member) $member = Member::currentUser();
|
||||
* return $member->inGroup('Editors');
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
@ -818,7 +818,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* @param $priority String left|right Determines who wins in case of a conflict (optional)
|
||||
* @param $includeRelations Boolean Merge any existing relations (optional)
|
||||
* @param $overwriteWithEmpty Boolean Overwrite existing left values with empty right values.
|
||||
* Only applicable with $priority='right'. (optional)
|
||||
* Only applicable with $priority='right'. (optional)
|
||||
* @return Boolean
|
||||
*/
|
||||
public function merge($rightObj, $priority = 'right', $includeRelations = true, $overwriteWithEmpty = false) {
|
||||
@ -997,7 +997,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
|
||||
if($defaults && !is_array($defaults)) {
|
||||
user_error("Bad '$this->class' defaults given: " . var_export($defaults, true),
|
||||
E_USER_WARNING);
|
||||
E_USER_WARNING);
|
||||
$defaults = null;
|
||||
}
|
||||
|
||||
@ -1258,8 +1258,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
. " Make sure that you call parent::onBeforeDelete().", E_USER_ERROR);
|
||||
}
|
||||
|
||||
// Deleting a record without an ID shouldn't do anything
|
||||
if(!$this->ID) throw new LogicException("DataObject::delete() called on a DataObject without an ID");
|
||||
// Deleting a record without an ID shouldn't do anything
|
||||
if(!$this->ID) throw new LogicException("DataObject::delete() called on a DataObject without an ID");
|
||||
|
||||
// TODO: This is quite ugly. To improve:
|
||||
// - move the details of the delete code in the DataQuery system
|
||||
@ -1868,8 +1868,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* Used by {@link SearchContext}.
|
||||
*
|
||||
* @param array $_params
|
||||
* 'fieldClasses': Associative array of field names as keys and FormField classes as values
|
||||
* 'restrictFields': Numeric array of a field name whitelist
|
||||
* 'fieldClasses': Associative array of field names as keys and FormField classes as values
|
||||
* 'restrictFields': Numeric array of a field name whitelist
|
||||
* @return FieldList
|
||||
*/
|
||||
public function scaffoldSearchFields($_params = null) {
|
||||
@ -1960,14 +1960,14 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* or extended onto it by using {@link DataExtension->updateCMSFields()}.
|
||||
*
|
||||
* <code>
|
||||
* klass MyCustomClass extends DataObject {
|
||||
* static $db = array('CustomProperty'=>'Boolean');
|
||||
* class MyCustomClass extends DataObject {
|
||||
* static $db = array('CustomProperty'=>'Boolean');
|
||||
*
|
||||
* function getCMSFields() {
|
||||
* $fields = parent::getCMSFields();
|
||||
* $fields->addFieldToTab('Root.Content',new CheckboxField('CustomProperty'));
|
||||
* return $fields;
|
||||
* }
|
||||
* function getCMSFields() {
|
||||
* $fields = parent::getCMSFields();
|
||||
* $fields->addFieldToTab('Root.Content',new CheckboxField('CustomProperty'));
|
||||
* return $fields;
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
@ -3130,8 +3130,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
// var_dump("{$ancestorClass}.{$type}_{$name}");
|
||||
$autoLabels[$name] = _t("{$ancestorClass}.{$type}_{$name}",FormField::name_to_label($name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$labels = array_merge((array)$autoLabels, (array)$customLabels);
|
||||
$this->extend('updateFieldLabels', $labels);
|
||||
@ -3278,7 +3278,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'MySQLDatabase' => 'ENGINE=MyISAM'
|
||||
* 'MySQLDatabase' => 'ENGINE=MyISAM'
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
@ -3321,8 +3321,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
*
|
||||
* Example:
|
||||
* array(
|
||||
* array('Title' => "DefaultPage1", 'PageTitle' => 'page1'),
|
||||
* array('Title' => "DefaultPage2")
|
||||
* array('Title' => "DefaultPage1", 'PageTitle' => 'page1'),
|
||||
* array('Title' => "DefaultPage2")
|
||||
* ).
|
||||
*
|
||||
* @var array
|
||||
@ -3378,7 +3378,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* Example code:
|
||||
* <code>
|
||||
* public static $many_many_extraFields = array(
|
||||
* 'Members' => array(
|
||||
* 'Members' => array(
|
||||
* 'Role' => 'Varchar(100)'
|
||||
* )
|
||||
* );
|
||||
@ -3408,8 +3408,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
*
|
||||
* Overriding the default filter, with a custom defined filter:
|
||||
* <code>
|
||||
* static $searchable_fields = array(
|
||||
* "Name" => "PartialMatchFilter"
|
||||
* static $searchable_fields = array(
|
||||
* "Name" => "PartialMatchFilter"
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
@ -3417,21 +3417,21 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* The 'filter' parameter will be generated from {@link DBField::$default_search_filter_class}.
|
||||
* The 'title' parameter will be generated from {@link DataObject->fieldLabels()}.
|
||||
* <code>
|
||||
* static $searchable_fields = array(
|
||||
* "Name" => array(
|
||||
* "field" => "TextField"
|
||||
* )
|
||||
* static $searchable_fields = array(
|
||||
* "Name" => array(
|
||||
* "field" => "TextField"
|
||||
* )
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* Overriding the default form field, filter and title:
|
||||
* <code>
|
||||
* static $searchable_fields = array(
|
||||
* "Organisation.ZipCode" => array(
|
||||
* "field" => "TextField",
|
||||
* "filter" => "PartialMatchFilter",
|
||||
* "title" => 'Organisation ZIP'
|
||||
* )
|
||||
* static $searchable_fields = array(
|
||||
* "Organisation.ZipCode" => array(
|
||||
* "field" => "TextField",
|
||||
* "filter" => "PartialMatchFilter",
|
||||
* "title" => 'Organisation ZIP'
|
||||
* )
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
@ -3483,21 +3483,21 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given method/parameter has a value
|
||||
* (Uses the DBField::hasValue if the parameter is a database field)
|
||||
*
|
||||
* Returns true if the given method/parameter has a value
|
||||
* (Uses the DBField::hasValue if the parameter is a database field)
|
||||
*
|
||||
* @param string $field The field name
|
||||
* @param array $arguments
|
||||
* @param bool $cache
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasValue($field, $arguments = null, $cache = true) {
|
||||
$obj = $this->dbObject($field);
|
||||
if($obj) {
|
||||
return $obj->exists();
|
||||
} else {
|
||||
return parent::hasValue($field, $arguments, $cache);
|
||||
}
|
||||
}
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasValue($field, $arguments = null, $cache = true) {
|
||||
$obj = $this->dbObject($field);
|
||||
if($obj) {
|
||||
return $obj->exists();
|
||||
} else {
|
||||
return parent::hasValue($field, $arguments, $cache);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ class DataQuery {
|
||||
* @param String $field Unquoted database column name (will be escaped automatically)
|
||||
*/
|
||||
public function max($field) {
|
||||
return $this->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)));
|
||||
return $this->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,7 +347,7 @@ class DataQuery {
|
||||
* @param String $field Unquoted database column name (will be escaped automatically)
|
||||
*/
|
||||
public function min($field) {
|
||||
return $this->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)));
|
||||
return $this->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,7 +356,7 @@ class DataQuery {
|
||||
* @param String $field Unquoted database column name (will be escaped automatically)
|
||||
*/
|
||||
public function avg($field) {
|
||||
return $this->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)));
|
||||
return $this->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -365,14 +365,14 @@ class DataQuery {
|
||||
* @param String $field Unquoted database column name (will be escaped automatically)
|
||||
*/
|
||||
public function sum($field) {
|
||||
return $this->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)));
|
||||
return $this->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a raw aggregate expression. Please handle escaping yourself
|
||||
*/
|
||||
public function aggregate($expression) {
|
||||
return $this->getFinalisedQuery()->aggregate($expression)->execute()->value();
|
||||
return $this->getFinalisedQuery()->aggregate($expression)->execute()->value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -567,74 +567,74 @@ class DataQuery {
|
||||
* @return The model class of the related item
|
||||
*/
|
||||
public function applyRelation($relation) {
|
||||
// NO-OP
|
||||
if(!$relation) return $this->dataClass;
|
||||
|
||||
if(is_string($relation)) $relation = explode(".", $relation);
|
||||
|
||||
$modelClass = $this->dataClass;
|
||||
|
||||
foreach($relation as $rel) {
|
||||
$model = singleton($modelClass);
|
||||
if ($component = $model->has_one($rel)) {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$foreignKey = $model->getReverseAssociation($component);
|
||||
$this->query->addLeftJoin($component,
|
||||
"\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");
|
||||
// NO-OP
|
||||
if(!$relation) return $this->dataClass;
|
||||
|
||||
if(is_string($relation)) $relation = explode(".", $relation);
|
||||
|
||||
$modelClass = $this->dataClass;
|
||||
|
||||
foreach($relation as $rel) {
|
||||
$model = singleton($modelClass);
|
||||
if ($component = $model->has_one($rel)) {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$foreignKey = $model->getReverseAssociation($component);
|
||||
$this->query->addLeftJoin($component,
|
||||
"\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");
|
||||
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on
|
||||
* its ancestor fields.
|
||||
*/
|
||||
$ancestry = ClassInfo::ancestry($component, true);
|
||||
if(!empty($ancestry)){
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$modelClass = $component;
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on
|
||||
* its ancestor fields.
|
||||
*/
|
||||
$ancestry = ClassInfo::ancestry($component, true);
|
||||
if(!empty($ancestry)){
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$modelClass = $component;
|
||||
|
||||
} elseif ($component = $model->has_many($rel)) {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$ancestry = $model->getClassAncestry();
|
||||
$foreignKey = $model->getRemoteJoinField($rel);
|
||||
$this->query->addLeftJoin($component,
|
||||
"\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on
|
||||
* its ancestor fields.
|
||||
*/
|
||||
$ancestry = ClassInfo::ancestry($component, true);
|
||||
if(!empty($ancestry)){
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$modelClass = $component;
|
||||
} elseif ($component = $model->has_many($rel)) {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$ancestry = $model->getClassAncestry();
|
||||
$foreignKey = $model->getRemoteJoinField($rel);
|
||||
$this->query->addLeftJoin($component,
|
||||
"\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on
|
||||
* its ancestor fields.
|
||||
*/
|
||||
$ancestry = ClassInfo::ancestry($component, true);
|
||||
if(!empty($ancestry)){
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$modelClass = $component;
|
||||
|
||||
} elseif ($component = $model->many_many($rel)) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component;
|
||||
$parentBaseClass = ClassInfo::baseDataClass($parentClass);
|
||||
$componentBaseClass = ClassInfo::baseDataClass($componentClass);
|
||||
$this->query->addInnerJoin($relationTable,
|
||||
"\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
|
||||
$this->query->addLeftJoin($componentBaseClass,
|
||||
"\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
|
||||
if(ClassInfo::hasTable($componentClass)) {
|
||||
$this->query->addLeftJoin($componentClass,
|
||||
"\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
|
||||
}
|
||||
$modelClass = $componentClass;
|
||||
} elseif ($component = $model->many_many($rel)) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component;
|
||||
$parentBaseClass = ClassInfo::baseDataClass($parentClass);
|
||||
$componentBaseClass = ClassInfo::baseDataClass($componentClass);
|
||||
$this->query->addInnerJoin($relationTable,
|
||||
"\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
|
||||
$this->query->addLeftJoin($componentBaseClass,
|
||||
"\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
|
||||
if(ClassInfo::hasTable($componentClass)) {
|
||||
$this->query->addLeftJoin($componentClass,
|
||||
"\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
|
||||
}
|
||||
$modelClass = $componentClass;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $modelClass;
|
||||
|
@ -422,7 +422,7 @@ abstract class SS_Database {
|
||||
//Indexes specified as arrays cannot be checked with this line: (it flattens out the array)
|
||||
if(!is_array($spec)) {
|
||||
$spec = preg_replace('/\s*,\s*/', ',', $spec);
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($this->tableList[strtolower($table)])) $newTable = true;
|
||||
|
||||
@ -1142,7 +1142,7 @@ abstract class SS_Query implements Iterator {
|
||||
$result .= "<tr>";
|
||||
foreach($record as $k => $v) {
|
||||
$result .= "<th>" . Convert::raw2xml($k) . "</th> ";
|
||||
}
|
||||
}
|
||||
$result .= "</tr> \n";
|
||||
}
|
||||
|
||||
@ -1219,7 +1219,7 @@ abstract class SS_Query implements Iterator {
|
||||
*/
|
||||
public function valid() {
|
||||
if(!$this->queryHasBegun) $this->next();
|
||||
return $this->currentRecord !== false;
|
||||
return $this->currentRecord !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,8 +298,8 @@ class DatabaseAdmin extends Controller {
|
||||
foreach($subclasses as $subclass) {
|
||||
$id = $record['ID'];
|
||||
if(($record['ClassName'] != $subclass) &&
|
||||
(!is_subclass_of($record['ClassName'], $subclass)) &&
|
||||
(isset($recordExists[$subclass][$id]))) {
|
||||
(!is_subclass_of($record['ClassName'], $subclass)) &&
|
||||
(isset($recordExists[$subclass][$id]))) {
|
||||
$sql = "DELETE FROM \"$subclass\" WHERE \"ID\" = $record[ID]";
|
||||
echo "<li>$sql";
|
||||
DB::query($sql);
|
||||
|
@ -66,10 +66,10 @@ class HasManyList extends RelationList {
|
||||
* @param $itemID The ID of the item to be removed
|
||||
*/
|
||||
public function removeByID($itemID) {
|
||||
$item = $this->byID($itemID);
|
||||
return $this->remove($item);
|
||||
}
|
||||
|
||||
$item = $this->byID($itemID);
|
||||
return $this->remove($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from this relation.
|
||||
* Doesn't actually remove the item, it just clears the foreign key value.
|
||||
@ -77,10 +77,10 @@ class HasManyList extends RelationList {
|
||||
* @todo Maybe we should delete the object instead?
|
||||
*/
|
||||
public function remove($item) {
|
||||
if(!($item instanceof $this->dataClass)) {
|
||||
throw new InvalidArgumentException("HasManyList::remove() expecting a $this->dataClass object, or ID",
|
||||
E_USER_ERROR);
|
||||
}
|
||||
if(!($item instanceof $this->dataClass)) {
|
||||
throw new InvalidArgumentException("HasManyList::remove() expecting a $this->dataClass object, or ID",
|
||||
E_USER_ERROR);
|
||||
}
|
||||
|
||||
$fk = $this->foreignKey;
|
||||
$item->$fk = null;
|
||||
|
@ -434,14 +434,14 @@ class Hierarchy extends DataExtension {
|
||||
public function Children() {
|
||||
if(!(isset($this->_cache_children) && $this->_cache_children)) {
|
||||
$result = $this->owner->stageChildren(false);
|
||||
if(isset($result)) {
|
||||
$this->_cache_children = new ArrayList();
|
||||
foreach($result as $child) {
|
||||
if($child->canView()) {
|
||||
$this->_cache_children->push($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isset($result)) {
|
||||
$this->_cache_children = new ArrayList();
|
||||
foreach($result as $child) {
|
||||
if($child->canView()) {
|
||||
$this->_cache_children->push($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->_cache_children;
|
||||
}
|
||||
@ -487,10 +487,10 @@ class Hierarchy extends DataExtension {
|
||||
// Next, go through the live children. Only some of these will be listed
|
||||
$liveChildren = $this->owner->liveChildren(true, true);
|
||||
if($liveChildren) {
|
||||
$merged = new ArrayList();
|
||||
$merged->merge($stageChildren);
|
||||
$merged->merge($liveChildren);
|
||||
$stageChildren = $merged;
|
||||
$merged = new ArrayList();
|
||||
$merged->merge($stageChildren);
|
||||
$merged->merge($liveChildren);
|
||||
$stageChildren = $merged;
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,7 +526,7 @@ class Hierarchy extends DataExtension {
|
||||
throw new Exception('Hierarchy->AllHistoricalChildren() only works with Versioned extension applied');
|
||||
}
|
||||
|
||||
return Versioned::get_including_deleted(ClassInfo::baseDataClass($this->owner->class),
|
||||
return Versioned::get_including_deleted(ClassInfo::baseDataClass($this->owner->class),
|
||||
"\"ParentID\" = " . (int)$this->owner->ID)->count();
|
||||
}
|
||||
|
||||
|
@ -117,11 +117,11 @@ class ManyManyList extends RelationList {
|
||||
* @param $itemID The ID of the item to remove.
|
||||
*/
|
||||
public function remove($item) {
|
||||
if(!($item instanceof $this->dataClass)) {
|
||||
throw new InvalidArgumentException("ManyManyList::remove() expecting a $this->dataClass object");
|
||||
}
|
||||
|
||||
return $this->removeByID($item->ID);
|
||||
if(!($item instanceof $this->dataClass)) {
|
||||
throw new InvalidArgumentException("ManyManyList::remove() expecting a $this->dataClass object");
|
||||
}
|
||||
|
||||
return $this->removeByID($item->ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +130,7 @@ class ManyManyList extends RelationList {
|
||||
* @param $itemID The item it
|
||||
*/
|
||||
public function removeByID($itemID) {
|
||||
if(!is_numeric($itemID)) throw new InvalidArgumentException("ManyManyList::removeById() expecting an ID");
|
||||
if(!is_numeric($itemID)) throw new InvalidArgumentException("ManyManyList::removeById() expecting an ID");
|
||||
|
||||
$query = new SQLQuery("*", array("\"$this->joinTable\""));
|
||||
$query->setDelete(true);
|
||||
@ -145,16 +145,16 @@ class ManyManyList extends RelationList {
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from this many-many join. To remove a subset of items, filter it first.
|
||||
*/
|
||||
public function removeAll() {
|
||||
/**
|
||||
* Remove all items from this many-many join. To remove a subset of items, filter it first.
|
||||
*/
|
||||
public function removeAll() {
|
||||
$query = $this->dataQuery()->query();
|
||||
$query->setDelete(true);
|
||||
$query->setSelect(array('*'));
|
||||
$query->setFrom("\"$this->joinTable\"");
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the extra field data for a single row of the relationship
|
||||
|
@ -269,8 +269,8 @@ class MySQLDatabase extends SS_Database {
|
||||
if($alteredIndexes) foreach($alteredIndexes as $k => $v) {
|
||||
$alterList[] .= "DROP INDEX \"$k\"";
|
||||
$alterList[] .= "ADD ". $this->getIndexSqlDefinition($k, $v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($alteredOptions && isset($alteredOptions[get_class($this)])) {
|
||||
if(!isset($this->indexList[$tableName])) {
|
||||
$this->indexList[$tableName] = $this->indexList($tableName);
|
||||
@ -298,7 +298,7 @@ class MySQLDatabase extends SS_Database {
|
||||
}
|
||||
}
|
||||
|
||||
$alterations = implode(",\n", $alterList);
|
||||
$alterations = implode(",\n", $alterList);
|
||||
$this->query("ALTER TABLE \"$tableName\" $alterations");
|
||||
}
|
||||
|
||||
@ -467,9 +467,9 @@ class MySQLDatabase extends SS_Database {
|
||||
|
||||
$indexSpec = trim($indexSpec);
|
||||
if($indexSpec[0] != '(') list($indexType, $indexFields) = explode(' ',$indexSpec,2);
|
||||
else $indexFields = $indexSpec;
|
||||
else $indexFields = $indexSpec;
|
||||
|
||||
if(!isset($indexType))
|
||||
if(!isset($indexType))
|
||||
$indexType = "index";
|
||||
|
||||
if($indexType=='using')
|
||||
@ -499,15 +499,15 @@ class MySQLDatabase extends SS_Database {
|
||||
$indexSpec=$this->convertIndexSpec($indexSpec);
|
||||
|
||||
$indexSpec = trim($indexSpec);
|
||||
if($indexSpec[0] != '(') {
|
||||
list($indexType, $indexFields) = explode(' ',$indexSpec,2);
|
||||
} else {
|
||||
$indexFields = $indexSpec;
|
||||
}
|
||||
if($indexSpec[0] != '(') {
|
||||
list($indexType, $indexFields) = explode(' ',$indexSpec,2);
|
||||
} else {
|
||||
$indexFields = $indexSpec;
|
||||
}
|
||||
|
||||
if(!$indexType) {
|
||||
$indexType = "index";
|
||||
}
|
||||
if(!$indexType) {
|
||||
$indexType = "index";
|
||||
}
|
||||
|
||||
$this->query("ALTER TABLE \"$tableName\" DROP INDEX \"$indexName\"");
|
||||
$this->query("ALTER TABLE \"$tableName\" ADD $indexType \"$indexName\" $indexFields");
|
||||
@ -822,19 +822,19 @@ class MySQLDatabase extends SS_Database {
|
||||
if(!class_exists('File')) throw new Exception('MySQLDatabase->searchEngine() requires "File" class');
|
||||
|
||||
$fileFilter = '';
|
||||
$keywords = Convert::raw2sql($keywords);
|
||||
$keywords = Convert::raw2sql($keywords);
|
||||
$htmlEntityKeywords = htmlentities($keywords, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$extraFilters = array('SiteTree' => '', 'File' => '');
|
||||
|
||||
if($booleanSearch) $boolean = "IN BOOLEAN MODE";
|
||||
if($booleanSearch) $boolean = "IN BOOLEAN MODE";
|
||||
|
||||
if($extraFilter) {
|
||||
$extraFilters['SiteTree'] = " AND $extraFilter";
|
||||
if($extraFilter) {
|
||||
$extraFilters['SiteTree'] = " AND $extraFilter";
|
||||
|
||||
if($alternativeFileFilter) $extraFilters['File'] = " AND $alternativeFileFilter";
|
||||
else $extraFilters['File'] = $extraFilters['SiteTree'];
|
||||
}
|
||||
if($alternativeFileFilter) $extraFilters['File'] = " AND $alternativeFileFilter";
|
||||
else $extraFilters['File'] = $extraFilters['SiteTree'];
|
||||
}
|
||||
|
||||
// Always ensure that only pages with ShowInSearch = 1 can be searched
|
||||
$extraFilters['SiteTree'] .= " AND ShowInSearch <> 0";
|
||||
@ -982,7 +982,7 @@ class MySQLDatabase extends SS_Database {
|
||||
$boolean = $booleanSearch ? "IN BOOLEAN MODE" : "";
|
||||
$fieldNames = '"' . implode('", "', $fields) . '"';
|
||||
|
||||
$SQL_keywords = Convert::raw2sql($keywords);
|
||||
$SQL_keywords = Convert::raw2sql($keywords);
|
||||
$SQL_htmlEntityKeywords = Convert::raw2sql(htmlentities($keywords, ENT_NOQUOTES, 'UTF-8'));
|
||||
|
||||
return "(MATCH ($fieldNames) AGAINST ('$SQL_keywords' $boolean) + MATCH ($fieldNames)"
|
||||
@ -1151,7 +1151,7 @@ class MySQLDatabase extends SS_Database {
|
||||
* @param string $date2 to be substracted of $date1, can be either 'now', literal datetime like
|
||||
* '1973-10-14 10:30:00' or field name, e.g. '"SiteTree"."Created"'
|
||||
* @return string SQL datetime expression to query for the interval between $date1 and $date2 in seconds which
|
||||
* is the result of the substraction
|
||||
* is the result of the substraction
|
||||
*/
|
||||
public function datetimeDifferenceClause($date1, $date2) {
|
||||
|
||||
|
@ -908,11 +908,11 @@ class SQLQuery {
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
try {
|
||||
return $this->sql();
|
||||
} catch(Exception $e) {
|
||||
return "<sql query>";
|
||||
}
|
||||
try {
|
||||
return $this->sql();
|
||||
} catch(Exception $e) {
|
||||
return "<sql query>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,6 +53,6 @@ class SS_Transliterator extends Object {
|
||||
* Transliteration using iconv()
|
||||
*/
|
||||
protected function useIconv($source) {
|
||||
return iconv("utf-8", "us-ascii//IGNORE//TRANSLIT", $source);
|
||||
return iconv("utf-8", "us-ascii//IGNORE//TRANSLIT", $source);
|
||||
}
|
||||
}
|
||||
|
@ -136,8 +136,8 @@ class Versioned extends DataExtension {
|
||||
* @todo Should this all go into VersionedDataQuery?
|
||||
*/
|
||||
public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) {
|
||||
$baseTable = ClassInfo::baseDataClass($dataQuery->dataClass());
|
||||
|
||||
$baseTable = ClassInfo::baseDataClass($dataQuery->dataClass());
|
||||
|
||||
switch($dataQuery->getQueryParam('Versioned.mode')) {
|
||||
// Noop
|
||||
case '':
|
||||
@ -266,8 +266,8 @@ class Versioned extends DataExtension {
|
||||
*/
|
||||
function augmentLoadLazyFields(SQLQuery &$query, DataQuery &$dataQuery = null, $record) {
|
||||
$dataClass = $dataQuery->dataClass();
|
||||
if (isset($record['Version'])){
|
||||
$dataQuery->where("\"$dataClass\".\"RecordID\" = " . $record['ID']);
|
||||
if (isset($record['Version'])){
|
||||
$dataQuery->where("\"$dataClass\".\"RecordID\" = " . $record['ID']);
|
||||
$dataQuery->where("\"$dataClass\".\"Version\" = " . $record['Version']);
|
||||
$dataQuery->setQueryParam('Versioned.mode', 'all_versions');
|
||||
}
|
||||
|
@ -330,23 +330,23 @@ class Date extends DBField {
|
||||
|
||||
|
||||
public function days_between($fyear, $fmonth, $fday, $tyear, $tmonth, $tday){
|
||||
return abs((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, $tmonth, $tday, $tyear))/(60*60*24));
|
||||
return abs((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, $tmonth, $tday, $tyear))/(60*60*24));
|
||||
}
|
||||
|
||||
public function day_before($fyear, $fmonth, $fday){
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-1,$fyear));
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-1,$fyear));
|
||||
}
|
||||
|
||||
public function next_day($fyear, $fmonth, $fday){
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday+1,$fyear));
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday+1,$fyear));
|
||||
}
|
||||
|
||||
public function weekday($fyear, $fmonth, $fday){ // 0 is a Monday
|
||||
return (((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
|
||||
return (((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
|
||||
}
|
||||
|
||||
public function prior_monday($fyear, $fmonth, $fday){
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-$this->weekday($fyear, $fmonth, $fday),$fyear));
|
||||
return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-$this->weekday($fyear, $fmonth, $fday),$fyear));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ class Text extends StringField {
|
||||
'NoHTML' => 'Text',
|
||||
);
|
||||
|
||||
/**
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see DBField::requireField()
|
||||
*/
|
||||
|
@ -17,8 +17,8 @@ class Varchar extends StringField {
|
||||
);
|
||||
|
||||
protected $size;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Construct a new short text field
|
||||
*
|
||||
* @param $name string The name of the field
|
||||
@ -27,12 +27,12 @@ class Varchar extends StringField {
|
||||
* See {@link StringField::setOptions()} for information on the available options
|
||||
* @return unknown_type
|
||||
*/
|
||||
public function __construct($name = null, $size = 50, $options = array()) {
|
||||
public function __construct($name = null, $size = 50, $options = array()) {
|
||||
$this->size = $size ? $size : 50;
|
||||
parent::__construct($name, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see DBField::requireField()
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@ class BBCodeParser extends TextParser {
|
||||
* @var Boolean
|
||||
*/
|
||||
protected static $allowSimilies = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the location of the smiles folder. By default use the ones in framework
|
||||
* but this can be overridden by setting BBCodeParser::set_icon_folder('themes/yourtheme/images/');
|
||||
@ -165,7 +165,7 @@ class BBCodeParser extends TextParser {
|
||||
'#(?<!\w):\((?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/sad.gif'> ", // :(
|
||||
'#(?<!\w):-\((?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/sad.gif'> ", // :-(
|
||||
'#(?<!\w):p(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/tongue.gif'> ", // :p
|
||||
'#(?<!\w)8-\)(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/cool.gif'> ", // 8-)
|
||||
'#(?<!\w)8-\)(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/cool.gif'> ", // 8-)
|
||||
'#(?<!\w):\^\)(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/confused.gif'> " // :^)
|
||||
);
|
||||
$this->content = preg_replace(array_keys($smilies), array_values($smilies), $this->content);
|
||||
|
@ -55,819 +55,818 @@
|
||||
*/
|
||||
class SSHTMLBBCodeParser
|
||||
{
|
||||
/**
|
||||
* An array of tags parsed by the engine, should be overwritten by filters
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_definedTags = array();
|
||||
/**
|
||||
* An array of tags parsed by the engine, should be overwritten by filters
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_definedTags = array();
|
||||
|
||||
/**
|
||||
* A string containing the input
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_text = '';
|
||||
/**
|
||||
* A string containing the input
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_text = '';
|
||||
|
||||
/**
|
||||
* A string containing the preparsed input
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_preparsed = '';
|
||||
/**
|
||||
* A string containing the preparsed input
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_preparsed = '';
|
||||
|
||||
/**
|
||||
* An array tags and texts build from the input text
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_tagArray = array();
|
||||
/**
|
||||
* An array tags and texts build from the input text
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_tagArray = array();
|
||||
|
||||
/**
|
||||
* A string containing the parsed version of the text
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_parsed = '';
|
||||
/**
|
||||
* A string containing the parsed version of the text
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_parsed = '';
|
||||
|
||||
/**
|
||||
* An array of options, filled by an ini file or through the contructor
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_options = array(
|
||||
'quotestyle' => 'double',
|
||||
'quotewhat' => 'all',
|
||||
'open' => '[',
|
||||
'close' => ']',
|
||||
'xmlclose' => true,
|
||||
'filters' => 'Basic'
|
||||
);
|
||||
/**
|
||||
* An array of options, filled by an ini file or through the contructor
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_options = array(
|
||||
'quotestyle' => 'double',
|
||||
'quotewhat' => 'all',
|
||||
'open' => '[',
|
||||
'close' => ']',
|
||||
'xmlclose' => true,
|
||||
'filters' => 'Basic'
|
||||
);
|
||||
|
||||
/**
|
||||
* An array of filters used for parsing
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_filters = array();
|
||||
/**
|
||||
* An array of filters used for parsing
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
var $_filters = array();
|
||||
|
||||
/**
|
||||
* Constructor, initialises the options and filters
|
||||
*
|
||||
* Sets the private variable _options with base options defined with
|
||||
* &PEAR::getStaticProperty(), overwriting them with (if present)
|
||||
* the argument to this method.
|
||||
* Then it sets the extra options to properly escape the tag
|
||||
* characters in preg_replace() etc. The set options are
|
||||
* then stored back with &PEAR::getStaticProperty(), so that the filter
|
||||
* classes can use them.
|
||||
* All the filters in the options are initialised and their defined tags
|
||||
* are copied into the private variable _definedTags.
|
||||
*
|
||||
* @param array options to use, can be left out
|
||||
* @return none
|
||||
* @access public
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function SSHTMLBBCodeParser($options = array())
|
||||
{
|
||||
// set the already set options
|
||||
$baseoptions = &SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser', '_options');
|
||||
if (is_array($baseoptions)) {
|
||||
foreach ($baseoptions as $k => $v) {
|
||||
$this->_options[$k] = $v;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructor, initialises the options and filters
|
||||
*
|
||||
* Sets the private variable _options with base options defined with
|
||||
* &PEAR::getStaticProperty(), overwriting them with (if present)
|
||||
* the argument to this method.
|
||||
* Then it sets the extra options to properly escape the tag
|
||||
* characters in preg_replace() etc. The set options are
|
||||
* then stored back with &PEAR::getStaticProperty(), so that the filter
|
||||
* classes can use them.
|
||||
* All the filters in the options are initialised and their defined tags
|
||||
* are copied into the private variable _definedTags.
|
||||
*
|
||||
* @param array options to use, can be left out
|
||||
* @return none
|
||||
* @access public
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function SSHTMLBBCodeParser($options = array())
|
||||
{
|
||||
// set the already set options
|
||||
$baseoptions = &SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser', '_options');
|
||||
if (is_array($baseoptions)) {
|
||||
foreach ($baseoptions as $k => $v) {
|
||||
$this->_options[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// set the options passed as an argument
|
||||
foreach ($options as $k => $v ) {
|
||||
$this->_options[$k] = $v;
|
||||
}
|
||||
// set the options passed as an argument
|
||||
foreach ($options as $k => $v ) {
|
||||
$this->_options[$k] = $v;
|
||||
}
|
||||
|
||||
// add escape open and close chars to the options for preg escaping
|
||||
$preg_escape = '\^$.[]|()?*+{}';
|
||||
if ($this->_options['open'] != '' && strpos($preg_escape, $this->_options['open'])) {
|
||||
$this->_options['open_esc'] = "\\".$this->_options['open'];
|
||||
} else {
|
||||
$this->_options['open_esc'] = $this->_options['open'];
|
||||
}
|
||||
if ($this->_options['close'] != '' && strpos($preg_escape, $this->_options['close'])) {
|
||||
$this->_options['close_esc'] = "\\".$this->_options['close'];
|
||||
} else {
|
||||
$this->_options['close_esc'] = $this->_options['close'];
|
||||
}
|
||||
// add escape open and close chars to the options for preg escaping
|
||||
$preg_escape = '\^$.[]|()?*+{}';
|
||||
if ($this->_options['open'] != '' && strpos($preg_escape, $this->_options['open'])) {
|
||||
$this->_options['open_esc'] = "\\".$this->_options['open'];
|
||||
} else {
|
||||
$this->_options['open_esc'] = $this->_options['open'];
|
||||
}
|
||||
if ($this->_options['close'] != '' && strpos($preg_escape, $this->_options['close'])) {
|
||||
$this->_options['close_esc'] = "\\".$this->_options['close'];
|
||||
} else {
|
||||
$this->_options['close_esc'] = $this->_options['close'];
|
||||
}
|
||||
|
||||
// set the options back so that child classes can use them */
|
||||
$baseoptions = $this->_options;
|
||||
unset($baseoptions);
|
||||
// set the options back so that child classes can use them */
|
||||
$baseoptions = $this->_options;
|
||||
unset($baseoptions);
|
||||
|
||||
// return if this is a subclass
|
||||
if (is_subclass_of($this, 'SSHTMLBBCodeParser_Filter')) {
|
||||
return;
|
||||
}
|
||||
// return if this is a subclass
|
||||
if (is_subclass_of($this, 'SSHTMLBBCodeParser_Filter')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// extract the definedTags from subclasses */
|
||||
$this->addFilters($this->_options['filters']);
|
||||
}
|
||||
|
||||
static function &getStaticProperty($class, $var)
|
||||
{
|
||||
static $properties;
|
||||
if (!isset($properties[$class])) {
|
||||
$properties[$class] = array();
|
||||
}
|
||||
if (!array_key_exists($var, $properties[$class])) {
|
||||
$properties[$class][$var] = null;
|
||||
}
|
||||
return $properties[$class][$var];
|
||||
}
|
||||
// extract the definedTags from subclasses */
|
||||
$this->addFilters($this->_options['filters']);
|
||||
}
|
||||
|
||||
static function &getStaticProperty($class, $var)
|
||||
{
|
||||
static $properties;
|
||||
if (!isset($properties[$class])) {
|
||||
$properties[$class] = array();
|
||||
}
|
||||
if (!array_key_exists($var, $properties[$class])) {
|
||||
$properties[$class][$var] = null;
|
||||
}
|
||||
return $properties[$class][$var];
|
||||
}
|
||||
|
||||
/**
|
||||
* Option setter
|
||||
*
|
||||
* @param string option name
|
||||
* @param mixed option value
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
$this->_options[$name] = $value;
|
||||
}
|
||||
/**
|
||||
* Option setter
|
||||
*
|
||||
* @param string option name
|
||||
* @param mixed option value
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
$this->_options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new filter
|
||||
*
|
||||
* @param string filter
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function addFilter($filter)
|
||||
{
|
||||
|
||||
$filter = ucfirst($filter);
|
||||
if (!array_key_exists($filter, $this->_filters)) {
|
||||
$class = 'SSHTMLBBCodeParser_Filter_'.$filter;
|
||||
if (fopen('BBCodeParser/Filter/'.$filter.'.php','r',true)) {
|
||||
include_once 'BBCodeParser/Filter/'.$filter.'.php';
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
/**
|
||||
* Add a new filter
|
||||
*
|
||||
* @param string filter
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function addFilter($filter)
|
||||
{
|
||||
$filter = ucfirst($filter);
|
||||
if (!array_key_exists($filter, $this->_filters)) {
|
||||
$class = 'SSHTMLBBCodeParser_Filter_'.$filter;
|
||||
if (fopen('BBCodeParser/Filter/'.$filter.'.php','r',true)) {
|
||||
include_once 'BBCodeParser/Filter/'.$filter.'.php';
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
|
||||
//PEAR::raiseError("Failed to load filter $filter", null, PEAR_ERROR_DIE);
|
||||
}
|
||||
//PEAR::raiseError("Failed to load filter $filter", null, PEAR_ERROR_DIE);
|
||||
}
|
||||
else {
|
||||
$this->_filters[$filter] = new $class;
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing filter
|
||||
*
|
||||
* @param string $filter
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function removeFilter($filter)
|
||||
{
|
||||
$filter = ucfirst(trim($filter));
|
||||
if (!empty($filter) && array_key_exists($filter, $this->_filters)) {
|
||||
unset($this->_filters[$filter]);
|
||||
}
|
||||
// also remove the related $this->_definedTags for this filter,
|
||||
// preserving the others
|
||||
$this->_definedTags = array();
|
||||
foreach (array_keys($this->_filters) as $filter) {
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove an existing filter
|
||||
*
|
||||
* @param string $filter
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function removeFilter($filter)
|
||||
{
|
||||
$filter = ucfirst(trim($filter));
|
||||
if (!empty($filter) && array_key_exists($filter, $this->_filters)) {
|
||||
unset($this->_filters[$filter]);
|
||||
}
|
||||
// also remove the related $this->_definedTags for this filter,
|
||||
// preserving the others
|
||||
$this->_definedTags = array();
|
||||
foreach (array_keys($this->_filters) as $filter) {
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new filters
|
||||
*
|
||||
* @param mixed (array or string)
|
||||
* @return boolean true if all ok, false if not.
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function addFilters($filters)
|
||||
{
|
||||
if (is_string($filters)) {
|
||||
//comma-separated list
|
||||
if (strpos($filters, ',') !== false) {
|
||||
$filters = explode(',', $filters);
|
||||
} else {
|
||||
$filters = array($filters);
|
||||
}
|
||||
}
|
||||
if (!is_array($filters)) {
|
||||
//invalid format
|
||||
return false;
|
||||
}
|
||||
foreach ($filters as $filter) {
|
||||
if (trim($filter)){
|
||||
$this->addFilter($filter);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Add new filters
|
||||
*
|
||||
* @param mixed (array or string)
|
||||
* @return boolean true if all ok, false if not.
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
public function addFilters($filters)
|
||||
{
|
||||
if (is_string($filters)) {
|
||||
//comma-separated list
|
||||
if (strpos($filters, ',') !== false) {
|
||||
$filters = explode(',', $filters);
|
||||
} else {
|
||||
$filters = array($filters);
|
||||
}
|
||||
}
|
||||
if (!is_array($filters)) {
|
||||
//invalid format
|
||||
return false;
|
||||
}
|
||||
foreach ($filters as $filter) {
|
||||
if (trim($filter)){
|
||||
$this->addFilter($filter);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes statements before the actual array building starts
|
||||
*
|
||||
* This method should be overwritten in a filter if you want to do
|
||||
* something before the parsing process starts. This can be useful to
|
||||
* allow certain short alternative tags which then can be converted into
|
||||
* proper tags with preg_replace() calls.
|
||||
* The main class walks through all the filters and and calls this
|
||||
* method. The filters should modify their private $_preparsed
|
||||
* variable, with input from $_text.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _preparse()
|
||||
{
|
||||
// default: assign _text to _preparsed, to be overwritten by filters
|
||||
$this->_preparsed = $this->_text;
|
||||
/**
|
||||
* Executes statements before the actual array building starts
|
||||
*
|
||||
* This method should be overwritten in a filter if you want to do
|
||||
* something before the parsing process starts. This can be useful to
|
||||
* allow certain short alternative tags which then can be converted into
|
||||
* proper tags with preg_replace() calls.
|
||||
* The main class walks through all the filters and and calls this
|
||||
* method. The filters should modify their private $_preparsed
|
||||
* variable, with input from $_text.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _preparse()
|
||||
{
|
||||
// default: assign _text to _preparsed, to be overwritten by filters
|
||||
$this->_preparsed = $this->_text;
|
||||
|
||||
// return if this is a subclass
|
||||
if (is_subclass_of($this, 'SSHTMLBBCodeParser')) {
|
||||
return;
|
||||
}
|
||||
// return if this is a subclass
|
||||
if (is_subclass_of($this, 'SSHTMLBBCodeParser')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// walk through the filters and execute _preparse
|
||||
foreach ($this->_filters as $filter) {
|
||||
$filter->setText($this->_preparsed);
|
||||
$filter->_preparse();
|
||||
$this->_preparsed = $filter->getPreparsed();
|
||||
}
|
||||
}
|
||||
// walk through the filters and execute _preparse
|
||||
foreach ($this->_filters as $filter) {
|
||||
$filter->setText($this->_preparsed);
|
||||
$filter->_preparse();
|
||||
$this->_preparsed = $filter->getPreparsed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tag array from the input string $_text
|
||||
*
|
||||
* An array consisting of tag and text elements is contructed from the
|
||||
* $_preparsed variable. The method uses _buildTag() to check if a tag is
|
||||
* valid and to build the actual tag to be added to the tag array.
|
||||
*
|
||||
* @todo - rewrite whole method, as this one is old and probably slow
|
||||
* - see if a recursive method would be better than an iterative one
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see _buildTag()
|
||||
* @see $_text
|
||||
* @see $_tagArray
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildTagArray()
|
||||
{
|
||||
$this->_tagArray = array();
|
||||
$str = $this->_preparsed;
|
||||
$strPos = 0;
|
||||
$strLength = strlen($str);
|
||||
/**
|
||||
* Builds the tag array from the input string $_text
|
||||
*
|
||||
* An array consisting of tag and text elements is contructed from the
|
||||
* $_preparsed variable. The method uses _buildTag() to check if a tag is
|
||||
* valid and to build the actual tag to be added to the tag array.
|
||||
*
|
||||
* @todo - rewrite whole method, as this one is old and probably slow
|
||||
* - see if a recursive method would be better than an iterative one
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see _buildTag()
|
||||
* @see $_text
|
||||
* @see $_tagArray
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildTagArray()
|
||||
{
|
||||
$this->_tagArray = array();
|
||||
$str = $this->_preparsed;
|
||||
$strPos = 0;
|
||||
$strLength = strlen($str);
|
||||
|
||||
while (($strPos < $strLength)) {
|
||||
$tag = array();
|
||||
$openPos = strpos($str, $this->_options['open'], $strPos);
|
||||
if ($openPos === false) {
|
||||
$openPos = $strLength;
|
||||
$nextOpenPos = $strLength;
|
||||
}
|
||||
if ($openPos + 1 > $strLength) {
|
||||
$nextOpenPos = $strLength;
|
||||
} else {
|
||||
$nextOpenPos = strpos($str, $this->_options['open'], $openPos + 1);
|
||||
if ($nextOpenPos === false) {
|
||||
$nextOpenPos = $strLength;
|
||||
}
|
||||
}
|
||||
$closePos = strpos($str, $this->_options['close'], $strPos);
|
||||
if ($closePos === false) {
|
||||
$closePos = $strLength + 1;
|
||||
}
|
||||
while (($strPos < $strLength)) {
|
||||
$tag = array();
|
||||
$openPos = strpos($str, $this->_options['open'], $strPos);
|
||||
if ($openPos === false) {
|
||||
$openPos = $strLength;
|
||||
$nextOpenPos = $strLength;
|
||||
}
|
||||
if ($openPos + 1 > $strLength) {
|
||||
$nextOpenPos = $strLength;
|
||||
} else {
|
||||
$nextOpenPos = strpos($str, $this->_options['open'], $openPos + 1);
|
||||
if ($nextOpenPos === false) {
|
||||
$nextOpenPos = $strLength;
|
||||
}
|
||||
}
|
||||
$closePos = strpos($str, $this->_options['close'], $strPos);
|
||||
if ($closePos === false) {
|
||||
$closePos = $strLength + 1;
|
||||
}
|
||||
|
||||
if ($openPos == $strPos) {
|
||||
if (($nextOpenPos < $closePos)) {
|
||||
// new open tag before closing tag: treat as text
|
||||
$newPos = $nextOpenPos;
|
||||
$tag['text'] = substr($str, $strPos, $nextOpenPos - $strPos);
|
||||
$tag['type'] = 0;
|
||||
} else {
|
||||
// possible valid tag
|
||||
$newPos = $closePos + 1;
|
||||
$newTag = $this->_buildTag(substr($str, $strPos, $closePos - $strPos + 1));
|
||||
if (($newTag !== false)) {
|
||||
$tag = $newTag;
|
||||
} else {
|
||||
// no valid tag after all
|
||||
$tag['text'] = substr($str, $strPos, $closePos - $strPos + 1);
|
||||
$tag['type'] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just text
|
||||
$newPos = $openPos;
|
||||
$tag['text'] = substr($str, $strPos, $openPos - $strPos);
|
||||
$tag['type'] = 0;
|
||||
}
|
||||
if ($openPos == $strPos) {
|
||||
if (($nextOpenPos < $closePos)) {
|
||||
// new open tag before closing tag: treat as text
|
||||
$newPos = $nextOpenPos;
|
||||
$tag['text'] = substr($str, $strPos, $nextOpenPos - $strPos);
|
||||
$tag['type'] = 0;
|
||||
} else {
|
||||
// possible valid tag
|
||||
$newPos = $closePos + 1;
|
||||
$newTag = $this->_buildTag(substr($str, $strPos, $closePos - $strPos + 1));
|
||||
if (($newTag !== false)) {
|
||||
$tag = $newTag;
|
||||
} else {
|
||||
// no valid tag after all
|
||||
$tag['text'] = substr($str, $strPos, $closePos - $strPos + 1);
|
||||
$tag['type'] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just text
|
||||
$newPos = $openPos;
|
||||
$tag['text'] = substr($str, $strPos, $openPos - $strPos);
|
||||
$tag['type'] = 0;
|
||||
}
|
||||
|
||||
// join 2 following text elements
|
||||
if ($tag['type'] === 0 && isset($prev) && $prev['type'] === 0) {
|
||||
$tag['text'] = $prev['text'].$tag['text'];
|
||||
array_pop($this->_tagArray);
|
||||
}
|
||||
// join 2 following text elements
|
||||
if ($tag['type'] === 0 && isset($prev) && $prev['type'] === 0) {
|
||||
$tag['text'] = $prev['text'].$tag['text'];
|
||||
array_pop($this->_tagArray);
|
||||
}
|
||||
|
||||
$this->_tagArray[] = $tag;
|
||||
$prev = $tag;
|
||||
$strPos = $newPos;
|
||||
}
|
||||
}
|
||||
$this->_tagArray[] = $tag;
|
||||
$prev = $tag;
|
||||
$strPos = $newPos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a tag from the input string
|
||||
*
|
||||
* This method builds a tag array based on the string it got as an
|
||||
* argument. If the tag is invalid, <false> is returned. The tag
|
||||
* attributes are extracted from the string and stored in the tag
|
||||
* array as an associative array.
|
||||
*
|
||||
* @param string string to build tag from
|
||||
* @return array tag in array format
|
||||
* @access private
|
||||
* @see _buildTagArray()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildTag($str)
|
||||
{
|
||||
$tag = array('text' => $str, 'attributes' => array());
|
||||
/**
|
||||
* Builds a tag from the input string
|
||||
*
|
||||
* This method builds a tag array based on the string it got as an
|
||||
* argument. If the tag is invalid, <false> is returned. The tag
|
||||
* attributes are extracted from the string and stored in the tag
|
||||
* array as an associative array.
|
||||
*
|
||||
* @param string string to build tag from
|
||||
* @return array tag in array format
|
||||
* @access private
|
||||
* @see _buildTagArray()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildTag($str)
|
||||
{
|
||||
$tag = array('text' => $str, 'attributes' => array());
|
||||
|
||||
if (substr($str, 1, 1) == '/') { // closing tag
|
||||
if (substr($str, 1, 1) == '/') { // closing tag
|
||||
|
||||
$tag['tag'] = strtolower(substr($str, 2, strlen($str) - 3));
|
||||
if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
|
||||
return false; // nope, it's not valid
|
||||
} else {
|
||||
$tag['type'] = 2;
|
||||
return $tag;
|
||||
}
|
||||
} else { // opening tag
|
||||
$tag['tag'] = strtolower(substr($str, 2, strlen($str) - 3));
|
||||
if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
|
||||
return false; // nope, it's not valid
|
||||
} else {
|
||||
$tag['type'] = 2;
|
||||
return $tag;
|
||||
}
|
||||
} else { // opening tag
|
||||
|
||||
$tag['type'] = 1;
|
||||
if (strpos($str, ' ') && (strpos($str, '=') === false)) {
|
||||
return false; // nope, it's not valid
|
||||
}
|
||||
$tag['type'] = 1;
|
||||
if (strpos($str, ' ') && (strpos($str, '=') === false)) {
|
||||
return false; // nope, it's not valid
|
||||
}
|
||||
|
||||
// tnx to Onno for the regex
|
||||
// split the tag with arguments and all
|
||||
$oe = $this->_options['open_esc'];
|
||||
$ce = $this->_options['close_esc'];
|
||||
$tagArray = array();
|
||||
if (preg_match("!$oe([a-z0-9]+)[^$ce]*$ce!i", $str, $tagArray) == 0) {
|
||||
return false;
|
||||
}
|
||||
$tag['tag'] = strtolower($tagArray[1]);
|
||||
if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
|
||||
return false; // nope, it's not valid
|
||||
}
|
||||
// tnx to Onno for the regex
|
||||
// split the tag with arguments and all
|
||||
$oe = $this->_options['open_esc'];
|
||||
$ce = $this->_options['close_esc'];
|
||||
$tagArray = array();
|
||||
if (preg_match("!$oe([a-z0-9]+)[^$ce]*$ce!i", $str, $tagArray) == 0) {
|
||||
return false;
|
||||
}
|
||||
$tag['tag'] = strtolower($tagArray[1]);
|
||||
if (!in_array($tag['tag'], array_keys($this->_definedTags))) {
|
||||
return false; // nope, it's not valid
|
||||
}
|
||||
|
||||
// tnx to Onno for the regex
|
||||
// validate the arguments
|
||||
$attributeArray = array();
|
||||
$regex = "![\s$oe]([a-z0-9]+)=(\"[^\s$ce]+\"|[^\s$ce]";
|
||||
if ($tag['tag'] != 'url') {
|
||||
$regex .= "[^=]";
|
||||
}
|
||||
$regex .= "+)(?=[\s$ce])!i";
|
||||
preg_match_all($regex, $str, $attributeArray, PREG_SET_ORDER);
|
||||
foreach ($attributeArray as $attribute) {
|
||||
$attNam = strtolower($attribute[1]);
|
||||
if (in_array($attNam, array_keys($this->_definedTags[$tag['tag']]['attributes']))) {
|
||||
if ($attribute[2][0] == '"' && $attribute[2][strlen($attribute[2])-1] == '"') {
|
||||
$tag['attributes'][$attNam] = substr($attribute[2], 1, -1);
|
||||
} else {
|
||||
$tag['attributes'][$attNam] = $attribute[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
// tnx to Onno for the regex
|
||||
// validate the arguments
|
||||
$attributeArray = array();
|
||||
$regex = "![\s$oe]([a-z0-9]+)=(\"[^\s$ce]+\"|[^\s$ce]";
|
||||
if ($tag['tag'] != 'url') {
|
||||
$regex .= "[^=]";
|
||||
}
|
||||
$regex .= "+)(?=[\s$ce])!i";
|
||||
preg_match_all($regex, $str, $attributeArray, PREG_SET_ORDER);
|
||||
foreach ($attributeArray as $attribute) {
|
||||
$attNam = strtolower($attribute[1]);
|
||||
if (in_array($attNam, array_keys($this->_definedTags[$tag['tag']]['attributes']))) {
|
||||
if ($attribute[2][0] == '"' && $attribute[2][strlen($attribute[2])-1] == '"') {
|
||||
$tag['attributes'][$attNam] = substr($attribute[2], 1, -1);
|
||||
} else {
|
||||
$tag['attributes'][$attNam] = $attribute[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tag array, regarding the allowed tags
|
||||
*
|
||||
* While looping through the tag array, two following text tags are
|
||||
* joined, and it is checked that the tag is allowed inside the
|
||||
* last opened tag.
|
||||
* By remembering what tags have been opened it is checked that
|
||||
* there is correct (xml compliant) nesting.
|
||||
* In the end all still opened tags are closed.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see _isAllowed()
|
||||
* @see $_tagArray
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>, Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _validateTagArray()
|
||||
{
|
||||
$newTagArray = array();
|
||||
$openTags = array();
|
||||
foreach ($this->_tagArray as $tag) {
|
||||
$prevTag = end($newTagArray);
|
||||
switch ($tag['type']) {
|
||||
case 0:
|
||||
if (($child = $this->_childNeeded(end($openTags), 'text')) &&
|
||||
$child !== false &&
|
||||
/*
|
||||
* No idea what to do in this case: A child is needed, but
|
||||
* no valid one is returned. We'll ignore it here and live
|
||||
* with it until someone reports a valid bug.
|
||||
*/
|
||||
$child !== true )
|
||||
{
|
||||
if (trim($tag['text']) == '') {
|
||||
//just an empty indentation or newline without value?
|
||||
continue;
|
||||
}
|
||||
$newTagArray[] = $child;
|
||||
$openTags[] = $child['tag'];
|
||||
}
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
break;
|
||||
/**
|
||||
* Validates the tag array, regarding the allowed tags
|
||||
*
|
||||
* While looping through the tag array, two following text tags are
|
||||
* joined, and it is checked that the tag is allowed inside the
|
||||
* last opened tag.
|
||||
* By remembering what tags have been opened it is checked that
|
||||
* there is correct (xml compliant) nesting.
|
||||
* In the end all still opened tags are closed.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see _isAllowed()
|
||||
* @see $_tagArray
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>, Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _validateTagArray()
|
||||
{
|
||||
$newTagArray = array();
|
||||
$openTags = array();
|
||||
foreach ($this->_tagArray as $tag) {
|
||||
$prevTag = end($newTagArray);
|
||||
switch ($tag['type']) {
|
||||
case 0:
|
||||
if (($child = $this->_childNeeded(end($openTags), 'text')) &&
|
||||
$child !== false &&
|
||||
/*
|
||||
* No idea what to do in this case: A child is needed, but
|
||||
* no valid one is returned. We'll ignore it here and live
|
||||
* with it until someone reports a valid bug.
|
||||
*/
|
||||
$child !== true )
|
||||
{
|
||||
if (trim($tag['text']) == '') {
|
||||
//just an empty indentation or newline without value?
|
||||
continue;
|
||||
}
|
||||
$newTagArray[] = $child;
|
||||
$openTags[] = $child['tag'];
|
||||
}
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!$this->_isAllowed(end($openTags), $tag['tag']) ||
|
||||
($parent = $this->_parentNeeded(end($openTags), $tag['tag'])) === true ||
|
||||
($child = $this->_childNeeded(end($openTags), $tag['tag'])) === true) {
|
||||
$tag['type'] = 0;
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
} else {
|
||||
if ($parent) {
|
||||
/*
|
||||
* Avoid use of parent if we can help it. If we are
|
||||
* trying to insert a new parent, but the current tag is
|
||||
* the same as the previous tag, then assume that the
|
||||
* previous tag structure is valid, and add this tag as
|
||||
* a sibling. To add as a sibling, we need to close the
|
||||
* current tag.
|
||||
*/
|
||||
if ($tag['tag'] == end($openTags)){
|
||||
$newTagArray[] = $this->_buildTag('[/'.$tag['tag'].']');
|
||||
array_pop($openTags);
|
||||
} else {
|
||||
$newTagArray[] = $parent;
|
||||
$openTags[] = $parent['tag'];
|
||||
}
|
||||
}
|
||||
if ($child) {
|
||||
$newTagArray[] = $child;
|
||||
$openTags[] = $child['tag'];
|
||||
}
|
||||
$openTags[] = $tag['tag'];
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
break;
|
||||
case 1:
|
||||
if (!$this->_isAllowed(end($openTags), $tag['tag']) ||
|
||||
($parent = $this->_parentNeeded(end($openTags), $tag['tag'])) === true ||
|
||||
($child = $this->_childNeeded(end($openTags), $tag['tag'])) === true) {
|
||||
$tag['type'] = 0;
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
} else {
|
||||
if ($parent) {
|
||||
/*
|
||||
* Avoid use of parent if we can help it. If we are
|
||||
* trying to insert a new parent, but the current tag is
|
||||
* the same as the previous tag, then assume that the
|
||||
* previous tag structure is valid, and add this tag as
|
||||
* a sibling. To add as a sibling, we need to close the
|
||||
* current tag.
|
||||
*/
|
||||
if ($tag['tag'] == end($openTags)){
|
||||
$newTagArray[] = $this->_buildTag('[/'.$tag['tag'].']');
|
||||
array_pop($openTags);
|
||||
} else {
|
||||
$newTagArray[] = $parent;
|
||||
$openTags[] = $parent['tag'];
|
||||
}
|
||||
}
|
||||
if ($child) {
|
||||
$newTagArray[] = $child;
|
||||
$openTags[] = $child['tag'];
|
||||
}
|
||||
$openTags[] = $tag['tag'];
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (($tag['tag'] == end($openTags) || $this->_isAllowed(end($openTags), $tag['tag']))) {
|
||||
if (in_array($tag['tag'], $openTags)) {
|
||||
$tmpOpenTags = array();
|
||||
while (end($openTags) != $tag['tag']) {
|
||||
$newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
|
||||
$tmpOpenTags[] = end($openTags);
|
||||
array_pop($openTags);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
array_pop($openTags);
|
||||
/* why is this here? it just seems to break things
|
||||
* (nested lists where closing tags need to be
|
||||
* generated)
|
||||
while (end($tmpOpenTags)) {
|
||||
$tmpTag = $this->_buildTag('['.end($tmpOpenTags).']');
|
||||
$newTagArray[] = $tmpTag;
|
||||
$openTags[] = $tmpTag['tag'];
|
||||
array_pop($tmpOpenTags);
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
$tag['type'] = 0;
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (end($openTags)) {
|
||||
$newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
|
||||
array_pop($openTags);
|
||||
}
|
||||
$this->_tagArray = $newTagArray;
|
||||
}
|
||||
case 2:
|
||||
if (($tag['tag'] == end($openTags) || $this->_isAllowed(end($openTags), $tag['tag']))) {
|
||||
if (in_array($tag['tag'], $openTags)) {
|
||||
$tmpOpenTags = array();
|
||||
while (end($openTags) != $tag['tag']) {
|
||||
$newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
|
||||
$tmpOpenTags[] = end($openTags);
|
||||
array_pop($openTags);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
array_pop($openTags);
|
||||
/* why is this here? it just seems to break things
|
||||
* (nested lists where closing tags need to be
|
||||
* generated)
|
||||
while (end($tmpOpenTags)) {
|
||||
$tmpTag = $this->_buildTag('['.end($tmpOpenTags).']');
|
||||
$newTagArray[] = $tmpTag;
|
||||
$openTags[] = $tmpTag['tag'];
|
||||
array_pop($tmpOpenTags);
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
$tag['type'] = 0;
|
||||
if ($prevTag['type'] === 0) {
|
||||
$tag['text'] = $prevTag['text'].$tag['text'];
|
||||
array_pop($newTagArray);
|
||||
}
|
||||
$newTagArray[] = $tag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (end($openTags)) {
|
||||
$newTagArray[] = $this->_buildTag('[/'.end($openTags).']');
|
||||
array_pop($openTags);
|
||||
}
|
||||
$this->_tagArray = $newTagArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a parent is needed
|
||||
*
|
||||
* Checks to see if the current $in tag has an appropriate parent. If it
|
||||
* does, then it returns false. If a parent is needed, then it returns the
|
||||
* first tag in the list to add to the stack.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean false if not needed, tag if needed, true if out
|
||||
* of our minds
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _parentNeeded($out, $in)
|
||||
{
|
||||
if (!isset($this->_definedTags[$in]['parent']) ||
|
||||
($this->_definedTags[$in]['parent'] == 'all')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Checks to see if a parent is needed
|
||||
*
|
||||
* Checks to see if the current $in tag has an appropriate parent. If it
|
||||
* does, then it returns false. If a parent is needed, then it returns the
|
||||
* first tag in the list to add to the stack.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean false if not needed, tag if needed, true if out
|
||||
* of our minds
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _parentNeeded($out, $in)
|
||||
{
|
||||
if (!isset($this->_definedTags[$in]['parent']) ||
|
||||
($this->_definedTags[$in]['parent'] == 'all')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ar = explode('^', $this->_definedTags[$in]['parent']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none'){
|
||||
if ($out && in_array($out, $tags)) {
|
||||
return false;
|
||||
}
|
||||
//Create a tag from the first one on the list
|
||||
return $this->_buildTag('['.$tags[0].']');
|
||||
}
|
||||
if ($ar[0] == 'all' && $out && !in_array($out, $tags)) {
|
||||
return false;
|
||||
}
|
||||
// Tag is needed, we don't know which one. We could make something up,
|
||||
// but it would be so random, I think that it would be worthless.
|
||||
return true;
|
||||
}
|
||||
$ar = explode('^', $this->_definedTags[$in]['parent']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none'){
|
||||
if ($out && in_array($out, $tags)) {
|
||||
return false;
|
||||
}
|
||||
//Create a tag from the first one on the list
|
||||
return $this->_buildTag('['.$tags[0].']');
|
||||
}
|
||||
if ($ar[0] == 'all' && $out && !in_array($out, $tags)) {
|
||||
return false;
|
||||
}
|
||||
// Tag is needed, we don't know which one. We could make something up,
|
||||
// but it would be so random, I think that it would be worthless.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a child is needed
|
||||
*
|
||||
* Checks to see if the current $out tag has an appropriate child. If it
|
||||
* does, then it returns false. If a child is needed, then it returns the
|
||||
* first tag in the list to add to the stack.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean false if not needed, tag if needed, true if out
|
||||
* of our minds
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _childNeeded($out, $in)
|
||||
{
|
||||
if (!isset($this->_definedTags[$out]['child']) ||
|
||||
($this->_definedTags[$out]['child'] == 'all')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Checks to see if a child is needed
|
||||
*
|
||||
* Checks to see if the current $out tag has an appropriate child. If it
|
||||
* does, then it returns false. If a child is needed, then it returns the
|
||||
* first tag in the list to add to the stack.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean false if not needed, tag if needed, true if out
|
||||
* of our minds
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Seth Price <seth@pricepages.org>
|
||||
*/
|
||||
public function _childNeeded($out, $in)
|
||||
{
|
||||
if (!isset($this->_definedTags[$out]['child']) ||
|
||||
($this->_definedTags[$out]['child'] == 'all')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ar = explode('^', $this->_definedTags[$out]['child']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none'){
|
||||
if ($in && in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
//Create a tag from the first one on the list
|
||||
return $this->_buildTag('['.$tags[0].']');
|
||||
}
|
||||
if ($ar[0] == 'all' && $in && !in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
// Tag is needed, we don't know which one. We could make something up,
|
||||
// but it would be so random, I think that it would be worthless.
|
||||
return true;
|
||||
}
|
||||
$ar = explode('^', $this->_definedTags[$out]['child']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none'){
|
||||
if ($in && in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
//Create a tag from the first one on the list
|
||||
return $this->_buildTag('['.$tags[0].']');
|
||||
}
|
||||
if ($ar[0] == 'all' && $in && !in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
// Tag is needed, we don't know which one. We could make something up,
|
||||
// but it would be so random, I think that it would be worthless.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a tag is allowed inside another tag
|
||||
*
|
||||
* The allowed tags are extracted from the private _definedTags array.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean return true if the tag is allowed, false
|
||||
* otherwise
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _isAllowed($out, $in)
|
||||
{
|
||||
if (!$out || ($this->_definedTags[$out]['allowed'] == 'all')) {
|
||||
return true;
|
||||
}
|
||||
if ($this->_definedTags[$out]['allowed'] == 'none') {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Checks to see if a tag is allowed inside another tag
|
||||
*
|
||||
* The allowed tags are extracted from the private _definedTags array.
|
||||
*
|
||||
* @param array tag that is on the outside
|
||||
* @param array tag that is on the inside
|
||||
* @return boolean return true if the tag is allowed, false
|
||||
* otherwise
|
||||
* @access private
|
||||
* @see _validateTagArray()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _isAllowed($out, $in)
|
||||
{
|
||||
if (!$out || ($this->_definedTags[$out]['allowed'] == 'all')) {
|
||||
return true;
|
||||
}
|
||||
if ($this->_definedTags[$out]['allowed'] == 'none') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ar = explode('^', $this->_definedTags[$out]['allowed']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none' && in_array($in, $tags)) {
|
||||
return true;
|
||||
}
|
||||
if ($ar[0] == 'all' && in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$ar = explode('^', $this->_definedTags[$out]['allowed']);
|
||||
$tags = explode(',', $ar[1]);
|
||||
if ($ar[0] == 'none' && in_array($in, $tags)) {
|
||||
return true;
|
||||
}
|
||||
if ($ar[0] == 'all' && in_array($in, $tags)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a parsed string based on the tag array
|
||||
*
|
||||
* The correct html and attribute values are extracted from the private
|
||||
* _definedTags array.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see $_tagArray
|
||||
* @see $_parsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildParsedString()
|
||||
{
|
||||
$this->_parsed = '';
|
||||
foreach ($this->_tagArray as $tag) {
|
||||
switch ($tag['type']) {
|
||||
/**
|
||||
* Builds a parsed string based on the tag array
|
||||
*
|
||||
* The correct html and attribute values are extracted from the private
|
||||
* _definedTags array.
|
||||
*
|
||||
* @return none
|
||||
* @access private
|
||||
* @see $_tagArray
|
||||
* @see $_parsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function _buildParsedString()
|
||||
{
|
||||
$this->_parsed = '';
|
||||
foreach ($this->_tagArray as $tag) {
|
||||
switch ($tag['type']) {
|
||||
|
||||
// just text
|
||||
case 0:
|
||||
$this->_parsed .= $tag['text'];
|
||||
break;
|
||||
// just text
|
||||
case 0:
|
||||
$this->_parsed .= $tag['text'];
|
||||
break;
|
||||
|
||||
// opening tag
|
||||
case 1:
|
||||
$this->_parsed .= '<'.$this->_definedTags[$tag['tag']]['htmlopen'];
|
||||
if ($this->_options['quotestyle'] == 'single') $q = "'";
|
||||
if ($this->_options['quotestyle'] == 'double') $q = '"';
|
||||
foreach ($tag['attributes'] as $a => $v) {
|
||||
//prevent XSS attacks. IMHO this is not enough, though...
|
||||
//@see http://pear.php.net/bugs/bug.php?id=5609
|
||||
$v = preg_replace('#(script|about|applet|activex|chrome):#is', "\\1:", $v);
|
||||
$v = htmlspecialchars($v);
|
||||
$v = str_replace('&amp;', '&', $v);
|
||||
// opening tag
|
||||
case 1:
|
||||
$this->_parsed .= '<'.$this->_definedTags[$tag['tag']]['htmlopen'];
|
||||
if ($this->_options['quotestyle'] == 'single') $q = "'";
|
||||
if ($this->_options['quotestyle'] == 'double') $q = '"';
|
||||
foreach ($tag['attributes'] as $a => $v) {
|
||||
//prevent XSS attacks. IMHO this is not enough, though...
|
||||
//@see http://pear.php.net/bugs/bug.php?id=5609
|
||||
$v = preg_replace('#(script|about|applet|activex|chrome):#is', "\\1:", $v);
|
||||
$v = htmlspecialchars($v);
|
||||
$v = str_replace('&amp;', '&', $v);
|
||||
|
||||
if (($this->_options['quotewhat'] == 'nothing') ||
|
||||
(($this->_options['quotewhat'] == 'strings') && is_numeric($v))
|
||||
) {
|
||||
$this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, '');
|
||||
} else {
|
||||
$this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, $q);
|
||||
}
|
||||
}
|
||||
if ($this->_definedTags[$tag['tag']]['htmlclose'] == '' && $this->_options['xmlclose']) {
|
||||
$this->_parsed .= ' /';
|
||||
}
|
||||
$this->_parsed .= '>';
|
||||
break;
|
||||
if (($this->_options['quotewhat'] == 'nothing') ||
|
||||
(($this->_options['quotewhat'] == 'strings') && is_numeric($v))
|
||||
) {
|
||||
$this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, '');
|
||||
} else {
|
||||
$this->_parsed .= ' '.sprintf($this->_definedTags[$tag['tag']]['attributes'][$a], $v, $q);
|
||||
}
|
||||
}
|
||||
if ($this->_definedTags[$tag['tag']]['htmlclose'] == '' && $this->_options['xmlclose']) {
|
||||
$this->_parsed .= ' /';
|
||||
}
|
||||
$this->_parsed .= '>';
|
||||
break;
|
||||
|
||||
// closing tag
|
||||
case 2:
|
||||
if ($this->_definedTags[$tag['tag']]['htmlclose'] != '') {
|
||||
$this->_parsed .= '</'.$this->_definedTags[$tag['tag']]['htmlclose'].'>';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// closing tag
|
||||
case 2:
|
||||
if ($this->_definedTags[$tag['tag']]['htmlclose'] != '') {
|
||||
$this->_parsed .= '</'.$this->_definedTags[$tag['tag']]['htmlclose'].'>';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets text in the object to be parsed
|
||||
*
|
||||
* @param string the text to set in the object
|
||||
* @return none
|
||||
* @access public
|
||||
* @see getText()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function setText($str)
|
||||
{
|
||||
$this->_text = $str;
|
||||
}
|
||||
/**
|
||||
* Sets text in the object to be parsed
|
||||
*
|
||||
* @param string the text to set in the object
|
||||
* @return none
|
||||
* @access public
|
||||
* @see getText()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function setText($str)
|
||||
{
|
||||
$this->_text = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unparsed text from the object
|
||||
*
|
||||
* @return string the text set in the object
|
||||
* @access public
|
||||
* @see setText()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->_text;
|
||||
}
|
||||
/**
|
||||
* Gets the unparsed text from the object
|
||||
*
|
||||
* @return string the text set in the object
|
||||
* @access public
|
||||
* @see setText()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preparsed text from the object
|
||||
*
|
||||
* @return string the text set in the object
|
||||
* @access public
|
||||
* @see _preparse()
|
||||
* @see $_preparsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getPreparsed()
|
||||
{
|
||||
return $this->_preparsed;
|
||||
}
|
||||
/**
|
||||
* Gets the preparsed text from the object
|
||||
*
|
||||
* @return string the text set in the object
|
||||
* @access public
|
||||
* @see _preparse()
|
||||
* @see $_preparsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getPreparsed()
|
||||
{
|
||||
return $this->_preparsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parsed text from the object
|
||||
*
|
||||
* @return string the parsed text set in the object
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_parsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getParsed()
|
||||
{
|
||||
return $this->_parsed;
|
||||
}
|
||||
/**
|
||||
* Gets the parsed text from the object
|
||||
*
|
||||
* @return string the parsed text set in the object
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_parsed
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function getParsed()
|
||||
{
|
||||
return $this->_parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the text set in the object
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see _preparse()
|
||||
* @see _buildTagArray()
|
||||
* @see _validateTagArray()
|
||||
* @see _buildParsedString()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function parse()
|
||||
{
|
||||
$this->_preparse();
|
||||
$this->_buildTagArray();
|
||||
$this->_validateTagArray();
|
||||
$this->_buildParsedString();
|
||||
}
|
||||
/**
|
||||
* Parses the text set in the object
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see _preparse()
|
||||
* @see _buildTagArray()
|
||||
* @see _validateTagArray()
|
||||
* @see _buildParsedString()
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function parse()
|
||||
{
|
||||
$this->_preparse();
|
||||
$this->_buildTagArray();
|
||||
$this->_validateTagArray();
|
||||
$this->_buildParsedString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick method to do setText(), parse() and getParsed at once
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function qparse($str)
|
||||
{
|
||||
$this->_text = $str;
|
||||
$this->parse();
|
||||
return $this->_parsed;
|
||||
}
|
||||
/**
|
||||
* Quick method to do setText(), parse() and getParsed at once
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function qparse($str)
|
||||
{
|
||||
$this->_text = $str;
|
||||
$this->parse();
|
||||
return $this->_parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick static method to do setText(), parse() and getParsed at once
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function staticQparse($str)
|
||||
{
|
||||
$p = new SSHTMLBBCodeParser();
|
||||
$str = $p->qparse($str);
|
||||
unset($p);
|
||||
return $str;
|
||||
}
|
||||
/**
|
||||
* Quick static method to do setText(), parse() and getParsed at once
|
||||
*
|
||||
* @return none
|
||||
* @access public
|
||||
* @see parse()
|
||||
* @see $_text
|
||||
* @author Stijn de Reede <sjr@gmx.co.uk>
|
||||
*/
|
||||
public function staticQparse($str)
|
||||
{
|
||||
$p = new SSHTMLBBCodeParser();
|
||||
$str = $p->qparse($str);
|
||||
unset($p);
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ class SearchContext extends Object {
|
||||
$searchParamArray = $searchParams;
|
||||
}
|
||||
|
||||
foreach($searchParamArray as $key => $value) {
|
||||
foreach($searchParamArray as $key => $value) {
|
||||
$key = str_replace('__', '.', $key);
|
||||
if($filter = $this->getFilter($key)) {
|
||||
$filter->setModel($this->modelClass);
|
||||
@ -158,9 +158,9 @@ class SearchContext extends Object {
|
||||
}
|
||||
}
|
||||
|
||||
if($this->connective != "AND") {
|
||||
throw new Exception("SearchContext connective '$this->connective' not supported after ORM-rewrite.");
|
||||
}
|
||||
if($this->connective != "AND") {
|
||||
throw new Exception("SearchContext connective '$this->connective' not supported after ORM-rewrite.");
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
@ -11,95 +11,95 @@
|
||||
*/
|
||||
abstract class Authenticator extends Object {
|
||||
|
||||
/**
|
||||
* This variable holds all authenticators that should be used
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $authenticators = array('MemberAuthenticator');
|
||||
|
||||
/**
|
||||
* Used to influence the order of authenticators on the login-screen
|
||||
* (default shows first).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $default_authenticator = 'MemberAuthenticator';
|
||||
/**
|
||||
* This variable holds all authenticators that should be used
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $authenticators = array('MemberAuthenticator');
|
||||
|
||||
/**
|
||||
* Used to influence the order of authenticators on the login-screen
|
||||
* (default shows first).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $default_authenticator = 'MemberAuthenticator';
|
||||
|
||||
|
||||
/**
|
||||
* Method to authenticate an user
|
||||
*
|
||||
* @param array $RAW_data Raw data to authenticate the user
|
||||
* @param Form $form Optional: If passed, better error messages can be
|
||||
* produced by using
|
||||
* {@link Form::sessionMessage()}
|
||||
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
||||
* the member object
|
||||
*/
|
||||
/**
|
||||
* Method to authenticate an user
|
||||
*
|
||||
* @param array $RAW_data Raw data to authenticate the user
|
||||
* @param Form $form Optional: If passed, better error messages can be
|
||||
* produced by using
|
||||
* {@link Form::sessionMessage()}
|
||||
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
||||
* the member object
|
||||
*/
|
||||
public static function authenticate($RAW_data, Form $form = null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that creates the login form for this authentication method
|
||||
*
|
||||
* @param Controller The parent controller, necessary to create the
|
||||
* appropriate form action tag
|
||||
* @return Form Returns the login form to use with this authentication
|
||||
* method
|
||||
*/
|
||||
/**
|
||||
* Method that creates the login form for this authentication method
|
||||
*
|
||||
* @param Controller The parent controller, necessary to create the
|
||||
* appropriate form action tag
|
||||
* @return Form Returns the login form to use with this authentication
|
||||
* method
|
||||
*/
|
||||
public static function get_login_form(Controller $controller) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the authentication method
|
||||
*
|
||||
* @return string Returns the name of the authentication method.
|
||||
*/
|
||||
/**
|
||||
* Get the name of the authentication method
|
||||
*
|
||||
* @return string Returns the name of the authentication method.
|
||||
*/
|
||||
public static function get_name() {
|
||||
}
|
||||
|
||||
public static function register($authenticator) {
|
||||
public static function register($authenticator) {
|
||||
self::register_authenticator($authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a new authenticator
|
||||
*
|
||||
* The new authenticator has to exist and to be derived from the
|
||||
* {@link Authenticator}.
|
||||
* Every authenticator can be registered only once.
|
||||
*
|
||||
* @param string $authenticator Name of the authenticator class to
|
||||
* register
|
||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
public static function register_authenticator($authenticator) {
|
||||
$authenticator = trim($authenticator);
|
||||
/**
|
||||
* Register a new authenticator
|
||||
*
|
||||
* The new authenticator has to exist and to be derived from the
|
||||
* {@link Authenticator}.
|
||||
* Every authenticator can be registered only once.
|
||||
*
|
||||
* @param string $authenticator Name of the authenticator class to
|
||||
* register
|
||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
public static function register_authenticator($authenticator) {
|
||||
$authenticator = trim($authenticator);
|
||||
|
||||
if(class_exists($authenticator) == false)
|
||||
return false;
|
||||
if(class_exists($authenticator) == false)
|
||||
return false;
|
||||
|
||||
if(is_subclass_of($authenticator, 'Authenticator') == false)
|
||||
return false;
|
||||
if(is_subclass_of($authenticator, 'Authenticator') == false)
|
||||
return false;
|
||||
|
||||
if(in_array($authenticator, self::$authenticators) == false) {
|
||||
if(call_user_func(array($authenticator, 'on_register')) === true) {
|
||||
array_push(self::$authenticators, $authenticator);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(in_array($authenticator, self::$authenticators) == false) {
|
||||
if(call_user_func(array($authenticator, 'on_register')) === true) {
|
||||
array_push(self::$authenticators, $authenticator);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function unregister($authenticator) {
|
||||
self::unregister_authenticator($authenticator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function unregister($authenticator) {
|
||||
self::unregister_authenticator($authenticator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a previously registered authenticator
|
||||
*
|
||||
@ -108,82 +108,82 @@ abstract class Authenticator extends Object {
|
||||
*/
|
||||
public static function unregister_authenticator($authenticator) {
|
||||
if(call_user_func(array($authenticator, 'on_unregister')) === true) {
|
||||
if(in_array($authenticator, self::$authenticators)) {
|
||||
unset(self::$authenticators[array_search($authenticator, self::$authenticators)]);
|
||||
}
|
||||
if(in_array($authenticator, self::$authenticators)) {
|
||||
unset(self::$authenticators[array_search($authenticator, self::$authenticators)]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a given authenticator is registered
|
||||
*
|
||||
* @param string $authenticator Name of the authenticator class to check
|
||||
* @return bool Returns TRUE if the authenticator is registered, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
public static function is_registered($authenticator) {
|
||||
return in_array($authenticator, self::$authenticators);
|
||||
}
|
||||
/**
|
||||
* Check if a given authenticator is registered
|
||||
*
|
||||
* @param string $authenticator Name of the authenticator class to check
|
||||
* @return bool Returns TRUE if the authenticator is registered, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
public static function is_registered($authenticator) {
|
||||
return in_array($authenticator, self::$authenticators);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all registered authenticators
|
||||
*
|
||||
* @return array Returns an array with the class names of all registered
|
||||
* authenticators.
|
||||
*/
|
||||
public static function get_authenticators() {
|
||||
// put default authenticator first (mainly for tab-order on loginform)
|
||||
if($key = array_search(self::$default_authenticator,self::$authenticators)) {
|
||||
unset(self::$authenticators[$key]);
|
||||
array_unshift(self::$authenticators, self::$default_authenticator);
|
||||
}
|
||||
/**
|
||||
* Get all registered authenticators
|
||||
*
|
||||
* @return array Returns an array with the class names of all registered
|
||||
* authenticators.
|
||||
*/
|
||||
public static function get_authenticators() {
|
||||
// put default authenticator first (mainly for tab-order on loginform)
|
||||
if($key = array_search(self::$default_authenticator,self::$authenticators)) {
|
||||
unset(self::$authenticators[$key]);
|
||||
array_unshift(self::$authenticators, self::$default_authenticator);
|
||||
}
|
||||
|
||||
return self::$authenticators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default authenticator (shows first in tabs)
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public static function set_default_authenticator($authenticator) {
|
||||
self::$default_authenticator = $authenticator;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_authenticator() {
|
||||
return self::$default_authenticator;
|
||||
}
|
||||
return self::$authenticators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default authenticator (shows first in tabs)
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public static function set_default_authenticator($authenticator) {
|
||||
self::$default_authenticator = $authenticator;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_authenticator() {
|
||||
return self::$default_authenticator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback function that is called when the authenticator is registered
|
||||
*
|
||||
* Use this method for initialization of a newly registered authenticator.
|
||||
* Just overload this method and it will be called when the authenticator
|
||||
* is registered.
|
||||
* <b>If the method returns FALSE, the authenticator won't be
|
||||
* registered!</b>
|
||||
*
|
||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
protected static function on_register() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function that is called when an authenticator is removed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function on_unregister() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Callback function that is called when the authenticator is registered
|
||||
*
|
||||
* Use this method for initialization of a newly registered authenticator.
|
||||
* Just overload this method and it will be called when the authenticator
|
||||
* is registered.
|
||||
* <b>If the method returns FALSE, the authenticator won't be
|
||||
* registered!</b>
|
||||
*
|
||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
protected static function on_register() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function that is called when an authenticator is removed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function on_unregister() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ class Group extends DataObject {
|
||||
// but tabstrip.js doesn't display tabs when directly adressed through a URL pragma
|
||||
_t('Group.RolesAddEditLink', 'Manage roles')
|
||||
) .
|
||||
"</p>"
|
||||
"</p>"
|
||||
)
|
||||
);
|
||||
|
||||
@ -315,7 +315,7 @@ class Group extends DataObject {
|
||||
}
|
||||
|
||||
public function getTreeTitle() {
|
||||
if($this->hasMethod('alternateTreeTitle')) return $this->alternateTreeTitle();
|
||||
if($this->hasMethod('alternateTreeTitle')) return $this->alternateTreeTitle();
|
||||
else return htmlspecialchars($this->Title, ENT_QUOTES);
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ class Group extends DataObject {
|
||||
$results = $this->extend('canEdit', $member);
|
||||
if($results && is_array($results)) if(!min($results)) return false;
|
||||
|
||||
if(
|
||||
if(
|
||||
// either we have an ADMIN
|
||||
(bool)Permission::checkMember($member, "ADMIN")
|
||||
|| (
|
||||
|
@ -561,7 +561,7 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
* It should return fields that are editable by the admin and the logged-in user.
|
||||
*
|
||||
* @return FieldList Returns a {@link FieldList} containing the fields for
|
||||
* the member form.
|
||||
* the member form.
|
||||
*/
|
||||
public function getMemberFormFields() {
|
||||
$fields = parent::getFrontendFields();
|
||||
@ -658,10 +658,10 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
|
||||
return $word . $number;
|
||||
} else {
|
||||
$random = rand();
|
||||
$string = md5($random);
|
||||
$output = substr($string, 0, 6);
|
||||
return $output;
|
||||
$random = rand();
|
||||
$string = md5($random);
|
||||
$output = substr($string, 0, 6);
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1149,7 +1149,7 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
*
|
||||
* @param array $groupList An array of group code names.
|
||||
* @param array $memberGroups A component set of groups (if set to NULL,
|
||||
* $this->groups() will be used)
|
||||
* $this->groups() will be used)
|
||||
* @return array Groups in which the member is NOT in.
|
||||
*/
|
||||
public function memberNotInGroups($groupList, $memberGroups = null){
|
||||
@ -1171,7 +1171,7 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
* this member.
|
||||
*
|
||||
* @return FieldList Return a FieldList of fields that would appropriate for
|
||||
* editing this member.
|
||||
* editing this member.
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
require_once('Zend/Date.php');
|
||||
@ -1535,14 +1535,14 @@ class Member_GroupSet extends ManyManyList {
|
||||
* @subpackage security
|
||||
*/
|
||||
class Member_ChangePasswordEmail extends Email {
|
||||
protected $from = ''; // setting a blank from address uses the site's default administrator email
|
||||
protected $subject = '';
|
||||
protected $ss_template = 'ChangePasswordEmail';
|
||||
|
||||
public function __construct() {
|
||||
protected $from = ''; // setting a blank from address uses the site's default administrator email
|
||||
protected $subject = '';
|
||||
protected $ss_template = 'ChangePasswordEmail';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->subject = _t('Member.SUBJECTPASSWORDCHANGED', "Your password has been changed", 'Email subject');
|
||||
}
|
||||
$this->subject = _t('Member.SUBJECTPASSWORDCHANGED', "Your password has been changed", 'Email subject');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1553,14 +1553,14 @@ class Member_ChangePasswordEmail extends Email {
|
||||
* @subpackage security
|
||||
*/
|
||||
class Member_ForgotPasswordEmail extends Email {
|
||||
protected $from = ''; // setting a blank from address uses the site's default administrator email
|
||||
protected $subject = '';
|
||||
protected $ss_template = 'ForgotPasswordEmail';
|
||||
|
||||
public function __construct() {
|
||||
protected $from = ''; // setting a blank from address uses the site's default administrator email
|
||||
protected $subject = '';
|
||||
protected $ss_template = 'ForgotPasswordEmail';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->subject = _t('Member.SUBJECTPASSWORDRESET', "Your password reset link", 'Email subject');
|
||||
}
|
||||
$this->subject = _t('Member.SUBJECTPASSWORDRESET', "Your password reset link", 'Email subject');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,103 +18,103 @@ class MemberAuthenticator extends Authenticator {
|
||||
'sha1' => 'sha1_v2.4'
|
||||
);
|
||||
|
||||
/**
|
||||
* Method to authenticate an user
|
||||
*
|
||||
* @param array $RAW_data Raw data to authenticate the user
|
||||
* @param Form $form Optional: If passed, better error messages can be
|
||||
* produced by using
|
||||
* {@link Form::sessionMessage()}
|
||||
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
||||
* the member object
|
||||
* @see Security::setDefaultAdmin()
|
||||
*/
|
||||
public static function authenticate($RAW_data, Form $form = null) {
|
||||
if(array_key_exists('Email', $RAW_data) && $RAW_data['Email']){
|
||||
$SQL_user = Convert::raw2sql($RAW_data['Email']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isLockedOut = false;
|
||||
$result = null;
|
||||
|
||||
// Default login (see Security::setDefaultAdmin())
|
||||
if(Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) {
|
||||
$member = Security::findAnAdministrator();
|
||||
} else {
|
||||
$member = DataObject::get_one(
|
||||
"Member",
|
||||
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user' AND \"Password\" IS NOT NULL"
|
||||
);
|
||||
|
||||
if($member) {
|
||||
$result = $member->checkPassword($RAW_data['Password']);
|
||||
} else {
|
||||
$result = new ValidationResult(false, _t('Member.ERRORWRONGCRED'));
|
||||
}
|
||||
|
||||
if($member && !$result->valid()) {
|
||||
$member->registerFailedLogin();
|
||||
$member = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally record every login attempt as a {@link LoginAttempt} object
|
||||
/**
|
||||
* TODO We could handle this with an extension
|
||||
* Method to authenticate an user
|
||||
*
|
||||
* @param array $RAW_data Raw data to authenticate the user
|
||||
* @param Form $form Optional: If passed, better error messages can be
|
||||
* produced by using
|
||||
* {@link Form::sessionMessage()}
|
||||
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
||||
* the member object
|
||||
* @see Security::setDefaultAdmin()
|
||||
*/
|
||||
if(Security::login_recording()) {
|
||||
$attempt = new LoginAttempt();
|
||||
if($member) {
|
||||
// successful login (member is existing with matching password)
|
||||
$attempt->MemberID = $member->ID;
|
||||
$attempt->Status = 'Success';
|
||||
|
||||
// Audit logging hook
|
||||
$member->extend('authenticated');
|
||||
public static function authenticate($RAW_data, Form $form = null) {
|
||||
if(array_key_exists('Email', $RAW_data) && $RAW_data['Email']){
|
||||
$SQL_user = Convert::raw2sql($RAW_data['Email']);
|
||||
} else {
|
||||
// failed login - we're trying to see if a user exists with this email (disregarding wrong passwords)
|
||||
$existingMember = DataObject::get_one(
|
||||
"Member",
|
||||
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user'"
|
||||
);
|
||||
if($existingMember) {
|
||||
$attempt->MemberID = $existingMember->ID;
|
||||
|
||||
// Audit logging hook
|
||||
$existingMember->extend('authenticationFailed');
|
||||
} else {
|
||||
|
||||
// Audit logging hook
|
||||
singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data);
|
||||
}
|
||||
$attempt->Status = 'Failure';
|
||||
}
|
||||
if(is_array($RAW_data['Email'])) {
|
||||
user_error("Bad email passed to MemberAuthenticator::authenticate(): $RAW_data[Email]", E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
$isLockedOut = false;
|
||||
$result = null;
|
||||
|
||||
// Default login (see Security::setDefaultAdmin())
|
||||
if(Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) {
|
||||
$member = Security::findAnAdministrator();
|
||||
} else {
|
||||
$member = DataObject::get_one(
|
||||
"Member",
|
||||
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user' AND \"Password\" IS NOT NULL"
|
||||
);
|
||||
|
||||
if($member) {
|
||||
$result = $member->checkPassword($RAW_data['Password']);
|
||||
} else {
|
||||
$result = new ValidationResult(false, _t('Member.ERRORWRONGCRED'));
|
||||
}
|
||||
|
||||
if($member && !$result->valid()) {
|
||||
$member->registerFailedLogin();
|
||||
$member = false;
|
||||
}
|
||||
}
|
||||
|
||||
$attempt->Email = $RAW_data['Email'];
|
||||
$attempt->IP = Controller::curr()->getRequest()->getIP();
|
||||
$attempt->write();
|
||||
}
|
||||
|
||||
// Legacy migration to precision-safe password hashes.
|
||||
// A login-event with cleartext passwords is the only time
|
||||
// when we can rehash passwords to a different hashing algorithm,
|
||||
// bulk-migration doesn't work due to the nature of hashing.
|
||||
// See PasswordEncryptor_LegacyPHPHash class.
|
||||
if(
|
||||
$member // only migrate after successful login
|
||||
&& self::$migrate_legacy_hashes
|
||||
&& array_key_exists($member->PasswordEncryption, self::$migrate_legacy_hashes)
|
||||
) {
|
||||
$member->Password = $RAW_data['Password'];
|
||||
$member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption];
|
||||
$member->write();
|
||||
}
|
||||
// Optionally record every login attempt as a {@link LoginAttempt} object
|
||||
/**
|
||||
* TODO We could handle this with an extension
|
||||
*/
|
||||
if(Security::login_recording()) {
|
||||
$attempt = new LoginAttempt();
|
||||
if($member) {
|
||||
// successful login (member is existing with matching password)
|
||||
$attempt->MemberID = $member->ID;
|
||||
$attempt->Status = 'Success';
|
||||
|
||||
// Audit logging hook
|
||||
$member->extend('authenticated');
|
||||
} else {
|
||||
// failed login - we're trying to see if a user exists with this email (disregarding wrong passwords)
|
||||
$existingMember = DataObject::get_one(
|
||||
"Member",
|
||||
"\"" . Member::get_unique_identifier_field() . "\" = '$SQL_user'"
|
||||
);
|
||||
if($existingMember) {
|
||||
$attempt->MemberID = $existingMember->ID;
|
||||
|
||||
// Audit logging hook
|
||||
$existingMember->extend('authenticationFailed');
|
||||
} else {
|
||||
|
||||
// Audit logging hook
|
||||
singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data);
|
||||
}
|
||||
$attempt->Status = 'Failure';
|
||||
}
|
||||
if(is_array($RAW_data['Email'])) {
|
||||
user_error("Bad email passed to MemberAuthenticator::authenticate(): $RAW_data[Email]", E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
$attempt->Email = $RAW_data['Email'];
|
||||
$attempt->IP = Controller::curr()->getRequest()->getIP();
|
||||
$attempt->write();
|
||||
}
|
||||
|
||||
// Legacy migration to precision-safe password hashes.
|
||||
// A login-event with cleartext passwords is the only time
|
||||
// when we can rehash passwords to a different hashing algorithm,
|
||||
// bulk-migration doesn't work due to the nature of hashing.
|
||||
// See PasswordEncryptor_LegacyPHPHash class.
|
||||
if(
|
||||
$member // only migrate after successful login
|
||||
&& self::$migrate_legacy_hashes
|
||||
&& array_key_exists($member->PasswordEncryption, self::$migrate_legacy_hashes)
|
||||
) {
|
||||
$member->Password = $RAW_data['Password'];
|
||||
$member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption];
|
||||
$member->write();
|
||||
}
|
||||
|
||||
if($member) {
|
||||
Session::clear('BackURL');
|
||||
@ -126,25 +126,25 @@ class MemberAuthenticator extends Authenticator {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method that creates the login form for this authentication method
|
||||
*
|
||||
* @param Controller The parent controller, necessary to create the
|
||||
* appropriate form action tag
|
||||
* @return Form Returns the login form to use with this authentication
|
||||
* method
|
||||
*/
|
||||
public static function get_login_form(Controller $controller) {
|
||||
return Object::create("MemberLoginForm", $controller, "LoginForm");
|
||||
}
|
||||
/**
|
||||
* Method that creates the login form for this authentication method
|
||||
*
|
||||
* @param Controller The parent controller, necessary to create the
|
||||
* appropriate form action tag
|
||||
* @return Form Returns the login form to use with this authentication
|
||||
* method
|
||||
*/
|
||||
public static function get_login_form(Controller $controller) {
|
||||
return Object::create("MemberLoginForm", $controller, "LoginForm");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the authentication method
|
||||
*
|
||||
* @return string Returns the name of the authentication method.
|
||||
*/
|
||||
public static function get_name() {
|
||||
/**
|
||||
* Get the name of the authentication method
|
||||
*
|
||||
* @return string Returns the name of the authentication method.
|
||||
*/
|
||||
public static function get_name() {
|
||||
return _t('MemberAuthenticator.TITLE', "E-mail & Password");
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class MemberLoginForm extends LoginForm {
|
||||
* @param string $authenticatorClassName Name of the authenticator class that this form uses.
|
||||
*/
|
||||
public function __construct($controller, $name, $fields = null, $actions = null,
|
||||
$checkCurrentUser = true) {
|
||||
$checkCurrentUser = true) {
|
||||
|
||||
// This is now set on the class directly to make it easier to create subclasses
|
||||
// $this->authenticator_class = $authenticatorClassName;
|
||||
@ -226,13 +226,13 @@ JS
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to authenticate the user
|
||||
*
|
||||
* @param array Submitted data
|
||||
* @return Member Returns the member object on successful authentication
|
||||
* or NULL on failure.
|
||||
*/
|
||||
/**
|
||||
* Try to authenticate the user
|
||||
*
|
||||
* @param array Submitted data
|
||||
* @return Member Returns the member object on successful authentication
|
||||
* or NULL on failure.
|
||||
*/
|
||||
public function performLogin($data) {
|
||||
$member = call_user_func_array(array($this->authenticator_class, 'authenticate'), array($data, $this));
|
||||
if($member) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
*/
|
||||
class Permission extends DataObject implements TemplateGlobalProvider {
|
||||
|
||||
// the (1) after Type specifies the DB default value which is needed for
|
||||
// the (1) after Type specifies the DB default value which is needed for
|
||||
// upgrades from older SilverStripe versions
|
||||
static $db = array(
|
||||
"Code" => "Varchar",
|
||||
@ -55,7 +55,7 @@ class Permission extends DataObject implements TemplateGlobalProvider {
|
||||
*/
|
||||
static $declared_permissions = null;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Linear list of declared permissions in the system.
|
||||
*
|
||||
* @var array
|
||||
|
@ -157,7 +157,7 @@ class PermissionCheckboxSetField extends FormField {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$odd = 0;
|
||||
$options = '';
|
||||
if($this->source) {
|
||||
@ -256,7 +256,7 @@ class PermissionCheckboxSetField extends FormField {
|
||||
|
||||
$idList = array();
|
||||
if($this->value) foreach($this->value as $id => $bool) {
|
||||
if($bool) {
|
||||
if($bool) {
|
||||
$perm = new $managedClass();
|
||||
$perm->{$this->filterField} = $record->ID;
|
||||
$perm->Code = $id;
|
||||
|
@ -7,18 +7,18 @@
|
||||
class Security extends Controller {
|
||||
|
||||
static $allowed_actions = array(
|
||||
'index',
|
||||
'login',
|
||||
'logout',
|
||||
'basicauthlogin',
|
||||
'lostpassword',
|
||||
'passwordsent',
|
||||
'changepassword',
|
||||
'index',
|
||||
'login',
|
||||
'logout',
|
||||
'basicauthlogin',
|
||||
'lostpassword',
|
||||
'passwordsent',
|
||||
'changepassword',
|
||||
'ping',
|
||||
'LoginForm',
|
||||
'ChangePasswordForm',
|
||||
'LostPasswordForm',
|
||||
);
|
||||
);
|
||||
|
||||
/**
|
||||
* Default user name. Only used in dev-mode by {@link setDefaultAdmin()}
|
||||
@ -138,22 +138,22 @@ class Security extends Controller {
|
||||
* If you don't provide a messageSet, a default will be used.
|
||||
*
|
||||
* @param Controller $controller The controller that you were on to cause the permission
|
||||
* failure.
|
||||
* failure.
|
||||
* @param string|array $messageSet The message to show to the user. This
|
||||
* can be a string, or a map of different
|
||||
* messages for different contexts.
|
||||
* If you pass an array, you can use the
|
||||
* following keys:
|
||||
* - default: The default message
|
||||
* - logInAgain: The message to show
|
||||
* if the user has just
|
||||
* logged out and the
|
||||
* - alreadyLoggedIn: The message to
|
||||
* show if the user
|
||||
* is already logged
|
||||
* in and lacks the
|
||||
* permission to
|
||||
* access the item.
|
||||
* can be a string, or a map of different
|
||||
* messages for different contexts.
|
||||
* If you pass an array, you can use the
|
||||
* following keys:
|
||||
* - default: The default message
|
||||
* - logInAgain: The message to show
|
||||
* if the user has just
|
||||
* logged out and the
|
||||
* - alreadyLoggedIn: The message to
|
||||
* show if the user
|
||||
* is already logged
|
||||
* in and lacks the
|
||||
* permission to
|
||||
* access the item.
|
||||
*
|
||||
* The alreadyLoggedIn value can contain a '%s' placeholder that will be replaced with a link
|
||||
* to log in.
|
||||
@ -240,7 +240,7 @@ class Security extends Controller {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the login form to process according to the submitted data
|
||||
*/
|
||||
protected function LoginForm() {
|
||||
@ -262,7 +262,7 @@ class Security extends Controller {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the login forms for all available authentication methods
|
||||
*
|
||||
* @return array Returns an array of available login forms (array of Form
|
||||
@ -276,8 +276,8 @@ class Security extends Controller {
|
||||
|
||||
$authenticators = Authenticator::get_authenticators();
|
||||
foreach($authenticators as $authenticator) {
|
||||
array_push($forms,
|
||||
call_user_func(array($authenticator, 'get_login_form'),
|
||||
array_push($forms,
|
||||
call_user_func(array($authenticator, 'get_login_form'),
|
||||
$this));
|
||||
}
|
||||
|
||||
@ -307,9 +307,9 @@ class Security extends Controller {
|
||||
* Log the currently logged in user out
|
||||
*
|
||||
* @param bool $redirect Redirect the user back to where they came.
|
||||
* - If it's false, the code calling logout() is
|
||||
* responsible for sending the user where-ever
|
||||
* they should go.
|
||||
* - If it's false, the code calling logout() is
|
||||
* responsible for sending the user where-ever
|
||||
* they should go.
|
||||
*/
|
||||
public function logout($redirect = true) {
|
||||
$member = Member::currentUser();
|
||||
@ -675,7 +675,7 @@ class Security extends Controller {
|
||||
}
|
||||
|
||||
if ($adminGroup) {
|
||||
$member = $adminGroup->Members()->First();
|
||||
$member = $adminGroup->Members()->First();
|
||||
}
|
||||
|
||||
if(!$adminGroup) {
|
||||
|
@ -37,7 +37,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$service->setQueryString($params);
|
||||
$responseBody = $service->request($url)->getBody();
|
||||
foreach ($params as $key => $value) {
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<get_item name=\"$key\">$value</get_item>", $responseBody);
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$service->setQueryString($params);
|
||||
$responseBody = $service->request($url)->getBody();
|
||||
foreach ($params as $key => $value) {
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<get_item name=\"$key\">$value</get_item>", $responseBody);
|
||||
}
|
||||
}
|
||||
@ -67,7 +67,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$url .= '?' . http_build_query($params);
|
||||
$responseBody = $service->request($url)->getBody();
|
||||
foreach ($params as $key => $value) {
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<request_item name=\"$key\">$value</request_item>", $responseBody);
|
||||
$this->assertContains("<get_item name=\"$key\">$value</get_item>", $responseBody);
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@
|
||||
namespace SilverStripe\Framework\Test\Behaviour;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeContext,
|
||||
SilverStripe\BehatExtension\Context\BasicContext,
|
||||
SilverStripe\BehatExtension\Context\LoginContext,
|
||||
SilverStripe\Framework\Test\Behaviour\CmsFormsContext,
|
||||
SilverStripe\Framework\Test\Behaviour\CmsUiContext;
|
||||
SilverStripe\BehatExtension\Context\BasicContext,
|
||||
SilverStripe\BehatExtension\Context\LoginContext,
|
||||
SilverStripe\Framework\Test\Behaviour\CmsFormsContext,
|
||||
SilverStripe\Framework\Test\Behaviour\CmsUiContext;
|
||||
|
||||
// PHPUnit
|
||||
require_once 'PHPUnit/Autoload.php';
|
||||
@ -20,19 +20,19 @@ require_once 'PHPUnit/Framework/Assert/Functions.php';
|
||||
*/
|
||||
class FeatureContext extends SilverStripeContext
|
||||
{
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->useContext('BasicContext', new BasicContext($parameters));
|
||||
$this->useContext('LoginContext', new LoginContext($parameters));
|
||||
$this->useContext('CmsFormsContext', new CmsFormsContext($parameters));
|
||||
$this->useContext('CmsUiContext', new CmsUiContext($parameters));
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->useContext('BasicContext', new BasicContext($parameters));
|
||||
$this->useContext('LoginContext', new LoginContext($parameters));
|
||||
$this->useContext('CmsFormsContext', new CmsFormsContext($parameters));
|
||||
$this->useContext('CmsUiContext', new CmsUiContext($parameters));
|
||||
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
namespace SilverStripe\Framework\Test\Behaviour;
|
||||
|
||||
use Behat\Behat\Context\ClosuredContextInterface,
|
||||
Behat\Behat\Context\TranslatedContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Exception\PendingException;
|
||||
Behat\Behat\Context\TranslatedContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Exception\PendingException;
|
||||
use Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
|
||||
// PHPUnit
|
||||
require_once 'PHPUnit/Autoload.php';
|
||||
@ -21,81 +21,81 @@ require_once 'PHPUnit/Framework/Assert/Functions.php';
|
||||
*/
|
||||
class CmsFormsContext extends BehatContext
|
||||
{
|
||||
protected $context;
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
}
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should see an edit page form$/
|
||||
*/
|
||||
public function stepIShouldSeeAnEditPageForm()
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
/**
|
||||
* @Then /^I should see an edit page form$/
|
||||
*/
|
||||
public function stepIShouldSeeAnEditPageForm()
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$form = $page->find('css', '#Form_EditForm');
|
||||
assertNotNull($form, 'I should see an edit page form');
|
||||
}
|
||||
$form = $page->find('css', '#Form_EditForm');
|
||||
assertNotNull($form, 'I should see an edit page form');
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I fill in the "(?P<field>([^"]*))" HTML field with "(?P<value>([^"]*))"$/
|
||||
* @When /^I fill in "(?P<value>([^"]*))" for the "(?P<field>([^"]*))" HTML field$/
|
||||
*/
|
||||
public function stepIFillInTheHtmlFieldWith($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
/**
|
||||
* @When /^I fill in the "(?P<field>([^"]*))" HTML field with "(?P<value>([^"]*))"$/
|
||||
* @When /^I fill in "(?P<value>([^"]*))" for the "(?P<field>([^"]*))" HTML field$/
|
||||
*/
|
||||
public function stepIFillInTheHtmlFieldWith($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
|
||||
$this->getSession()->evaluateScript(sprintf(
|
||||
"jQuery('#%s').entwine('ss').getEditor().setContent('%s')",
|
||||
$inputField->getAttribute('id'),
|
||||
addcslashes($value, "'")
|
||||
));
|
||||
}
|
||||
$this->getSession()->evaluateScript(sprintf(
|
||||
"jQuery('#%s').entwine('ss').getEditor().setContent('%s')",
|
||||
$inputField->getAttribute('id'),
|
||||
addcslashes($value, "'")
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I append "(?P<value>([^"]*))" to the "(?P<field>([^"]*))" HTML field$/
|
||||
*/
|
||||
public function stepIAppendTotheHtmlField($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
/**
|
||||
* @When /^I append "(?P<value>([^"]*))" to the "(?P<field>([^"]*))" HTML field$/
|
||||
*/
|
||||
public function stepIAppendTotheHtmlField($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
|
||||
$this->getSession()->evaluateScript(sprintf(
|
||||
"jQuery('#%s').entwine('ss').getEditor().insertContent('%s')",
|
||||
$inputField->getAttribute('id'),
|
||||
addcslashes($value, "'")
|
||||
));
|
||||
}
|
||||
$this->getSession()->evaluateScript(sprintf(
|
||||
"jQuery('#%s').entwine('ss').getEditor().insertContent('%s')",
|
||||
$inputField->getAttribute('id'),
|
||||
addcslashes($value, "'")
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the "(?P<field>([^"]*))" HTML field should contain "(?P<value>([^"]*))"$/
|
||||
*/
|
||||
public function theHtmlFieldShouldContain($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
/**
|
||||
* @Then /^the "(?P<field>([^"]*))" HTML field should contain "(?P<value>([^"]*))"$/
|
||||
*/
|
||||
public function theHtmlFieldShouldContain($field, $value)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$inputField = $page->findField($field);
|
||||
assertNotNull($inputField, sprintf('HTML field "%s" not found', $field));
|
||||
|
||||
$this->getMainContext()->assertElementContains('#' . $inputField->getAttribute('id'), $value);
|
||||
}
|
||||
$this->getMainContext()->assertElementContains('#' . $inputField->getAttribute('id'), $value);
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,13 @@
|
||||
namespace SilverStripe\Framework\Test\Behaviour;
|
||||
|
||||
use Behat\Behat\Context\ClosuredContextInterface,
|
||||
Behat\Behat\Context\TranslatedContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Exception\PendingException,
|
||||
Behat\Mink\Exception\ElementNotFoundException;
|
||||
Behat\Behat\Context\TranslatedContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Exception\PendingException,
|
||||
Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
|
||||
|
||||
// PHPUnit
|
||||
@ -23,376 +23,376 @@ require_once 'PHPUnit/Framework/Assert/Functions.php';
|
||||
*/
|
||||
class CmsUiContext extends BehatContext
|
||||
{
|
||||
protected $context;
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
}
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should see the CMS$/
|
||||
*/
|
||||
public function iShouldSeeTheCms()
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_element = $page->find('css', '.cms');
|
||||
assertNotNull($cms_element, 'CMS not found');
|
||||
}
|
||||
/**
|
||||
* @Then /^I should see the CMS$/
|
||||
*/
|
||||
public function iShouldSeeTheCms()
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_element = $page->find('css', '.cms');
|
||||
assertNotNull($cms_element, 'CMS not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should see a "([^"]*)" notice$/
|
||||
*/
|
||||
public function iShouldSeeANotice($notice)
|
||||
{
|
||||
$this->getMainContext()->assertElementContains('.notice-wrap', $notice);
|
||||
}
|
||||
/**
|
||||
* @Then /^I should see a "([^"]*)" notice$/
|
||||
*/
|
||||
public function iShouldSeeANotice($notice)
|
||||
{
|
||||
$this->getMainContext()->assertElementContains('.notice-wrap', $notice);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should see a "([^"]*)" message$/
|
||||
*/
|
||||
public function iShouldSeeAMessage($message)
|
||||
{
|
||||
$this->getMainContext()->assertElementContains('.message', $message);
|
||||
}
|
||||
/**
|
||||
* @Then /^I should see a "([^"]*)" message$/
|
||||
*/
|
||||
public function iShouldSeeAMessage($message)
|
||||
{
|
||||
$this->getMainContext()->assertElementContains('.message', $message);
|
||||
}
|
||||
|
||||
protected function getCmsTabsElement()
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.cms-content-header-tabs').size() > 0");
|
||||
protected function getCmsTabsElement()
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.cms-content-header-tabs').size() > 0");
|
||||
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_content_header_tabs = $page->find('css', '.cms-content-header-tabs');
|
||||
assertNotNull($cms_content_header_tabs, 'CMS tabs not found');
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_content_header_tabs = $page->find('css', '.cms-content-header-tabs');
|
||||
assertNotNull($cms_content_header_tabs, 'CMS tabs not found');
|
||||
|
||||
return $cms_content_header_tabs;
|
||||
}
|
||||
return $cms_content_header_tabs;
|
||||
}
|
||||
|
||||
protected function getCmsContentToolbarElement()
|
||||
{
|
||||
$this->getSession()->wait(
|
||||
5000,
|
||||
"window.jQuery('.cms-content-toolbar').size() > 0 "
|
||||
. "&& window.jQuery('.cms-content-toolbar').children().size() > 0"
|
||||
);
|
||||
protected function getCmsContentToolbarElement()
|
||||
{
|
||||
$this->getSession()->wait(
|
||||
5000,
|
||||
"window.jQuery('.cms-content-toolbar').size() > 0 "
|
||||
. "&& window.jQuery('.cms-content-toolbar').children().size() > 0"
|
||||
);
|
||||
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_content_toolbar_element = $page->find('css', '.cms-content-toolbar');
|
||||
assertNotNull($cms_content_toolbar_element, 'CMS content toolbar not found');
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_content_toolbar_element = $page->find('css', '.cms-content-toolbar');
|
||||
assertNotNull($cms_content_toolbar_element, 'CMS content toolbar not found');
|
||||
|
||||
return $cms_content_toolbar_element;
|
||||
}
|
||||
return $cms_content_toolbar_element;
|
||||
}
|
||||
|
||||
protected function getCmsTreeElement()
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.cms-tree').size() > 0");
|
||||
protected function getCmsTreeElement()
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.cms-tree').size() > 0");
|
||||
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_tree_element = $page->find('css', '.cms-tree');
|
||||
assertNotNull($cms_tree_element, 'CMS tree not found');
|
||||
$page = $this->getSession()->getPage();
|
||||
$cms_tree_element = $page->find('css', '.cms-tree');
|
||||
assertNotNull($cms_tree_element, 'CMS tree not found');
|
||||
|
||||
return $cms_tree_element;
|
||||
}
|
||||
return $cms_tree_element;
|
||||
}
|
||||
|
||||
protected function getGridfieldTable($title)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$table_elements = $page->findAll('css', '.ss-gridfield-table');
|
||||
assertNotNull($table_elements, 'Table elements not found');
|
||||
protected function getGridfieldTable($title)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$table_elements = $page->findAll('css', '.ss-gridfield-table');
|
||||
assertNotNull($table_elements, 'Table elements not found');
|
||||
|
||||
$table_element = null;
|
||||
foreach ($table_elements as $table) {
|
||||
$table_title_element = $table->find('css', '.title');
|
||||
if ($table_title_element->getText() === $title) {
|
||||
$table_element = $table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull($table_element, sprintf('Table `%s` not found', $title));
|
||||
$table_element = null;
|
||||
foreach ($table_elements as $table) {
|
||||
$table_title_element = $table->find('css', '.title');
|
||||
if ($table_title_element->getText() === $title) {
|
||||
$table_element = $table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull($table_element, sprintf('Table `%s` not found', $title));
|
||||
|
||||
return $table_element;
|
||||
}
|
||||
return $table_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I should see a "([^"]*)" button in CMS Content Toolbar$/
|
||||
*/
|
||||
public function iShouldSeeAButtonInCmsContentToolbar($text)
|
||||
{
|
||||
$cms_content_toolbar_element = $this->getCmsContentToolbarElement();
|
||||
/**
|
||||
* @Given /^I should see a "([^"]*)" button in CMS Content Toolbar$/
|
||||
*/
|
||||
public function iShouldSeeAButtonInCmsContentToolbar($text)
|
||||
{
|
||||
$cms_content_toolbar_element = $this->getCmsContentToolbarElement();
|
||||
|
||||
$element = $cms_content_toolbar_element->find('named', array('link_or_button', "'$text'"));
|
||||
assertNotNull($element, sprintf('%s button not found', $text));
|
||||
}
|
||||
$element = $cms_content_toolbar_element->find('named', array('link_or_button', "'$text'"));
|
||||
assertNotNull($element, sprintf('%s button not found', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I should see "([^"]*)" in CMS Tree$/
|
||||
*/
|
||||
public function stepIShouldSeeInCmsTree($text)
|
||||
{
|
||||
$cms_tree_element = $this->getCmsTreeElement();
|
||||
/**
|
||||
* @When /^I should see "([^"]*)" in CMS Tree$/
|
||||
*/
|
||||
public function stepIShouldSeeInCmsTree($text)
|
||||
{
|
||||
$cms_tree_element = $this->getCmsTreeElement();
|
||||
|
||||
$element = $cms_tree_element->find('named', array('content', "'$text'"));
|
||||
assertNotNull($element, sprintf('%s not found', $text));
|
||||
}
|
||||
$element = $cms_tree_element->find('named', array('content', "'$text'"));
|
||||
assertNotNull($element, sprintf('%s not found', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I should not see "([^"]*)" in CMS Tree$/
|
||||
*/
|
||||
public function stepIShouldNotSeeInCmsTree($text)
|
||||
{
|
||||
$cms_tree_element = $this->getCmsTreeElement();
|
||||
/**
|
||||
* @When /^I should not see "([^"]*)" in CMS Tree$/
|
||||
*/
|
||||
public function stepIShouldNotSeeInCmsTree($text)
|
||||
{
|
||||
$cms_tree_element = $this->getCmsTreeElement();
|
||||
|
||||
$element = $cms_tree_element->find('named', array('content', "'$text'"));
|
||||
assertNull($element, sprintf('%s found', $text));
|
||||
}
|
||||
$element = $cms_tree_element->find('named', array('content', "'$text'"));
|
||||
assertNull($element, sprintf('%s found', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I expand the "([^"]*)" CMS Panel$/
|
||||
*/
|
||||
public function iExpandTheCmsPanel()
|
||||
{
|
||||
// TODO Make dynamic, currently hardcoded to first panel
|
||||
$page = $this->getSession()->getPage();
|
||||
/**
|
||||
* @When /^I expand the "([^"]*)" CMS Panel$/
|
||||
*/
|
||||
public function iExpandTheCmsPanel()
|
||||
{
|
||||
// TODO Make dynamic, currently hardcoded to first panel
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$panel_toggle_element = $page->find('css', '.cms-content > .cms-panel > .cms-panel-toggle > .toggle-expand');
|
||||
assertNotNull($panel_toggle_element, 'Panel toggle not found');
|
||||
$panel_toggle_element = $page->find('css', '.cms-content > .cms-panel > .cms-panel-toggle > .toggle-expand');
|
||||
assertNotNull($panel_toggle_element, 'Panel toggle not found');
|
||||
|
||||
if ($panel_toggle_element->isVisible()) {
|
||||
$panel_toggle_element->click();
|
||||
}
|
||||
}
|
||||
if ($panel_toggle_element->isVisible()) {
|
||||
$panel_toggle_element->click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I click the "([^"]*)" CMS tab$/
|
||||
*/
|
||||
public function iClickTheCmsTab($tab)
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.ui-tabs-nav').size() > 0");
|
||||
/**
|
||||
* @When /^I click the "([^"]*)" CMS tab$/
|
||||
*/
|
||||
public function iClickTheCmsTab($tab)
|
||||
{
|
||||
$this->getSession()->wait(5000, "window.jQuery('.ui-tabs-nav').size() > 0");
|
||||
|
||||
$page = $this->getSession()->getPage();
|
||||
$tabsets = $page->findAll('css', '.ui-tabs-nav');
|
||||
assertNotNull($tabsets, 'CMS tabs not found');
|
||||
$page = $this->getSession()->getPage();
|
||||
$tabsets = $page->findAll('css', '.ui-tabs-nav');
|
||||
assertNotNull($tabsets, 'CMS tabs not found');
|
||||
|
||||
$tab_element = null;
|
||||
foreach($tabsets as $tabset) {
|
||||
if($tab_element) continue;
|
||||
$tab_element = $tabset->find('named', array('link_or_button', "'$tab'"));
|
||||
}
|
||||
assertNotNull($tab_element, sprintf('%s tab not found', $tab));
|
||||
$tab_element = null;
|
||||
foreach($tabsets as $tabset) {
|
||||
if($tab_element) continue;
|
||||
$tab_element = $tabset->find('named', array('link_or_button', "'$tab'"));
|
||||
}
|
||||
assertNotNull($tab_element, sprintf('%s tab not found', $tab));
|
||||
|
||||
$tab_element->click();
|
||||
}
|
||||
$tab_element->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldContain($table, $text)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldContain($table, $text)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
|
||||
$element = $table_element->find('named', array('content', "'$text'"));
|
||||
assertNotNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table));
|
||||
}
|
||||
$element = $table_element->find('named', array('content', "'$text'"));
|
||||
assertNotNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should not contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldNotContain($table, $text)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should not contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldNotContain($table, $text)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
|
||||
$element = $table_element->find('named', array('content', "'$text'"));
|
||||
assertNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table));
|
||||
}
|
||||
$element = $table_element->find('named', array('content', "'$text'"));
|
||||
assertNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I click on "([^"]*)" in the "([^"]*)" table$/
|
||||
*/
|
||||
public function iClickOnInTheTable($text, $table)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
/**
|
||||
* @Given /^I click on "([^"]*)" in the "([^"]*)" table$/
|
||||
*/
|
||||
public function iClickOnInTheTable($text, $table)
|
||||
{
|
||||
$table_element = $this->getGridfieldTable($table);
|
||||
|
||||
$element = $table_element->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text));
|
||||
assertNotNull($element, sprintf('Element containing `%s` not found', $text));
|
||||
$element->click();
|
||||
}
|
||||
$element = $table_element->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text));
|
||||
assertNotNull($element, sprintf('Element containing `%s` not found', $text));
|
||||
$element->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I can see the preview panel$/
|
||||
*/
|
||||
public function iCanSeeThePreviewPanel()
|
||||
{
|
||||
$this->getMainContext()->assertElementOnPage('.cms-preview');
|
||||
}
|
||||
/**
|
||||
* @Then /^I can see the preview panel$/
|
||||
*/
|
||||
public function iCanSeeThePreviewPanel()
|
||||
{
|
||||
$this->getMainContext()->assertElementOnPage('.cms-preview');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^the preview contains "([^"]*)"$/
|
||||
*/
|
||||
public function thePreviewContains($content)
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
/**
|
||||
* @Given /^the preview contains "([^"]*)"$/
|
||||
*/
|
||||
public function thePreviewContains($content)
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
|
||||
$this->getMainContext()->assertPageContainsText($content);
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
$this->getMainContext()->assertPageContainsText($content);
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I set the CMS mode to "([^"]*)"$/
|
||||
*/
|
||||
public function iSetTheCmsToMode($mode)
|
||||
{
|
||||
return array(
|
||||
new Step\When(sprintf('I fill in the "Change view mode" dropdown with "%s"', $mode)),
|
||||
new Step\When('I wait for 1 second') // wait for CMS layout to redraw
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @Given /^I set the CMS mode to "([^"]*)"$/
|
||||
*/
|
||||
public function iSetTheCmsToMode($mode)
|
||||
{
|
||||
return array(
|
||||
new Step\When(sprintf('I fill in the "Change view mode" dropdown with "%s"', $mode)),
|
||||
new Step\When('I wait for 1 second') // wait for CMS layout to redraw
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I wait for the preview to load$/
|
||||
*/
|
||||
public function iWaitForThePreviewToLoad()
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
|
||||
$this->getSession()->wait(
|
||||
5000,
|
||||
"!jQuery('iframe[name=cms-preview-iframe]').hasClass('loading')"
|
||||
);
|
||||
/**
|
||||
* @Given /^I wait for the preview to load$/
|
||||
*/
|
||||
public function iWaitForThePreviewToLoad()
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
|
||||
$this->getSession()->wait(
|
||||
5000,
|
||||
"!jQuery('iframe[name=cms-preview-iframe]').hasClass('loading')"
|
||||
);
|
||||
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I switch the preview to "([^"]*)"$/
|
||||
*/
|
||||
public function iSwitchThePreviewToMode($mode)
|
||||
{
|
||||
$controls = $this->getSession()->getPage()->find('css', '.cms-preview-controls');
|
||||
assertNotNull($controls, 'Preview controls not found');
|
||||
/**
|
||||
* @Given /^I switch the preview to "([^"]*)"$/
|
||||
*/
|
||||
public function iSwitchThePreviewToMode($mode)
|
||||
{
|
||||
$controls = $this->getSession()->getPage()->find('css', '.cms-preview-controls');
|
||||
assertNotNull($controls, 'Preview controls not found');
|
||||
|
||||
$label = $controls->find('xpath', sprintf(
|
||||
'.//label[(@for="%s")]',
|
||||
$mode
|
||||
));
|
||||
assertNotNull($label, 'Preview mode switch not found');
|
||||
$label = $controls->find('xpath', sprintf(
|
||||
'.//label[(@for="%s")]',
|
||||
$mode
|
||||
));
|
||||
assertNotNull($label, 'Preview mode switch not found');
|
||||
|
||||
$label->click();
|
||||
$label->click();
|
||||
|
||||
return new Step\When('I wait for the preview to load');
|
||||
}
|
||||
return new Step\When('I wait for the preview to load');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^the preview does not contain "([^"]*)"$/
|
||||
*/
|
||||
public function thePreviewDoesNotContain($content)
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
/**
|
||||
* @Given /^the preview does not contain "([^"]*)"$/
|
||||
*/
|
||||
public function thePreviewDoesNotContain($content)
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
$driver->switchToIFrame('cms-preview-iframe');
|
||||
|
||||
$this->getMainContext()->assertPageNotContainsText($content);
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
$this->getMainContext()->assertPageNotContainsText($content);
|
||||
$driver->switchToWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround for chosen.js dropdowns which hide the original dropdown field.
|
||||
*
|
||||
* @When /^(?:|I )fill in the "(?P<field>(?:[^"]|\\")*)" dropdown with "(?P<value>(?:[^"]|\\")*)"$/
|
||||
* @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" dropdown$/
|
||||
*/
|
||||
public function theIFillInTheDropdownWith($field, $value)
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
$value = $this->fixStepArgument($value);
|
||||
/**
|
||||
* Workaround for chosen.js dropdowns which hide the original dropdown field.
|
||||
*
|
||||
* @When /^(?:|I )fill in the "(?P<field>(?:[^"]|\\")*)" dropdown with "(?P<value>(?:[^"]|\\")*)"$/
|
||||
* @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" dropdown$/
|
||||
*/
|
||||
public function theIFillInTheDropdownWith($field, $value)
|
||||
{
|
||||
$field = $this->fixStepArgument($field);
|
||||
$value = $this->fixStepArgument($value);
|
||||
|
||||
// Given the fuzzy matching, we might get more than one matching field.
|
||||
$formFields = array();
|
||||
// Given the fuzzy matching, we might get more than one matching field.
|
||||
$formFields = array();
|
||||
|
||||
// Find by label
|
||||
$formField = $this->getSession()->getPage()->findField($field);
|
||||
if($formField) $formFields[] = $formField;
|
||||
// Find by label
|
||||
$formField = $this->getSession()->getPage()->findField($field);
|
||||
if($formField) $formFields[] = $formField;
|
||||
|
||||
// Fall back to finding by title (for dropdowns without a label)
|
||||
if(!$formFields) {
|
||||
$formFields = $this->getSession()->getPage()->findAll(
|
||||
'xpath',
|
||||
sprintf(
|
||||
'//*[self::select][(./@title="%s")]',
|
||||
$field
|
||||
)
|
||||
);
|
||||
}
|
||||
// Fall back to finding by title (for dropdowns without a label)
|
||||
if(!$formFields) {
|
||||
$formFields = $this->getSession()->getPage()->findAll(
|
||||
'xpath',
|
||||
sprintf(
|
||||
'//*[self::select][(./@title="%s")]',
|
||||
$field
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
assertGreaterThan(0, count($formFields), sprintf(
|
||||
'Chosen.js dropdown named "%s" not found',
|
||||
$field
|
||||
));
|
||||
assertGreaterThan(0, count($formFields), sprintf(
|
||||
'Chosen.js dropdown named "%s" not found',
|
||||
$field
|
||||
));
|
||||
|
||||
$containers = array();
|
||||
foreach($formFields as $formField) {
|
||||
// Traverse up to field holder
|
||||
$containerCandidate = $formField;
|
||||
do {
|
||||
$containerCandidate = $containerCandidate->getParent();
|
||||
} while($containerCandidate && !preg_match('/field/', $containerCandidate->getAttribute('class')));
|
||||
$containers = array();
|
||||
foreach($formFields as $formField) {
|
||||
// Traverse up to field holder
|
||||
$containerCandidate = $formField;
|
||||
do {
|
||||
$containerCandidate = $containerCandidate->getParent();
|
||||
} while($containerCandidate && !preg_match('/field/', $containerCandidate->getAttribute('class')));
|
||||
|
||||
if(
|
||||
$containerCandidate
|
||||
&& $containerCandidate->isVisible()
|
||||
&& preg_match('/field/', $containerCandidate->getAttribute('class'))
|
||||
) {
|
||||
$containers[] = $containerCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
assertGreaterThan(0, count($containers), 'Chosen.js field container not found');
|
||||
if(
|
||||
$containerCandidate
|
||||
&& $containerCandidate->isVisible()
|
||||
&& preg_match('/field/', $containerCandidate->getAttribute('class'))
|
||||
) {
|
||||
$containers[] = $containerCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
assertGreaterThan(0, count($containers), 'Chosen.js field container not found');
|
||||
|
||||
// Default to first visible container
|
||||
$container = $containers[0];
|
||||
|
||||
// Click on newly expanded list element, indirectly setting the dropdown value
|
||||
$linkEl = $container->find('xpath', './/a[./@href]');
|
||||
assertNotNull($linkEl, 'Chosen.js link element not found');
|
||||
$this->getSession()->wait(100); // wait for dropdown overlay to appear
|
||||
$linkEl->click();
|
||||
// Default to first visible container
|
||||
$container = $containers[0];
|
||||
|
||||
// Click on newly expanded list element, indirectly setting the dropdown value
|
||||
$linkEl = $container->find('xpath', './/a[./@href]');
|
||||
assertNotNull($linkEl, 'Chosen.js link element not found');
|
||||
$this->getSession()->wait(100); // wait for dropdown overlay to appear
|
||||
$linkEl->click();
|
||||
|
||||
$listEl = $container->find('xpath', sprintf('.//li[contains(normalize-space(string(.)), \'%s\')]', $value));
|
||||
assertNotNull($listEl, sprintf(
|
||||
'Chosen.js list element with title "%s" not found',
|
||||
$value
|
||||
));
|
||||
$listEl = $container->find('xpath', sprintf('.//li[contains(normalize-space(string(.)), \'%s\')]', $value));
|
||||
assertNotNull($listEl, sprintf(
|
||||
'Chosen.js list element with title "%s" not found',
|
||||
$value
|
||||
));
|
||||
|
||||
// Dropdown flyout might be animated
|
||||
// $this->getSession()->wait(1000, 'jQuery(":animated").length == 0');
|
||||
$this->getSession()->wait(300);
|
||||
// Dropdown flyout might be animated
|
||||
// $this->getSession()->wait(1000, 'jQuery(":animated").length == 0');
|
||||
$this->getSession()->wait(300);
|
||||
|
||||
$listEl->click();
|
||||
}
|
||||
$listEl->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fixed step argument (with \\" replaced back to ").
|
||||
*
|
||||
* @param string $argument
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fixStepArgument($argument)
|
||||
{
|
||||
return str_replace('\\"', '"', $argument);
|
||||
}
|
||||
/**
|
||||
* Returns fixed step argument (with \\" replaced back to ").
|
||||
*
|
||||
* @param string $argument
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function fixStepArgument($argument)
|
||||
{
|
||||
return str_replace('\\"', '"', $argument);
|
||||
}
|
||||
}
|
||||
|
@ -27,18 +27,18 @@ if(!defined('BASE_PATH')) define('BASE_PATH', dirname($frameworkPath));
|
||||
|
||||
// Copied from cli-script.php, to enable same behaviour through phpunit runner.
|
||||
if(isset($_SERVER['argv'][2])) {
|
||||
$args = array_slice($_SERVER['argv'],2);
|
||||
if(!isset($_GET)) $_GET = array();
|
||||
if(!isset($_REQUEST)) $_REQUEST = array();
|
||||
foreach($args as $arg) {
|
||||
if(strpos($arg,'=') == false) {
|
||||
$_GET['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str( (substr($arg,0,2) == '--') ? substr($arg,2) : $arg, $newItems );
|
||||
$_GET = array_merge($_GET, $newItems);
|
||||
}
|
||||
}
|
||||
$args = array_slice($_SERVER['argv'],2);
|
||||
if(!isset($_GET)) $_GET = array();
|
||||
if(!isset($_REQUEST)) $_REQUEST = array();
|
||||
foreach($args as $arg) {
|
||||
if(strpos($arg,'=') == false) {
|
||||
$_GET['args'][] = $arg;
|
||||
} else {
|
||||
$newItems = array();
|
||||
parse_str( (substr($arg,0,2) == '--') ? substr($arg,2) : $arg, $newItems );
|
||||
$_GET = array_merge($_GET, $newItems);
|
||||
}
|
||||
}
|
||||
$_REQUEST = array_merge($_REQUEST, $_GET);
|
||||
}
|
||||
|
||||
@ -70,4 +70,4 @@ if(!isset($_GET['flush']) || !$_GET['flush']) {
|
||||
"Add flush=1 as an argument to discover new classes or files.\n",
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ class HTTPTest extends SapphireTest {
|
||||
/**
|
||||
* Tests {@link HTTP::getLinksIn()}
|
||||
*/
|
||||
public function testGetLinksIn() {
|
||||
$content = '
|
||||
public function testGetLinksIn() {
|
||||
$content = '
|
||||
<h2><a href="/">My Cool Site</a></h2>
|
||||
|
||||
<p>
|
||||
@ -26,13 +26,13 @@ class HTTPTest extends SapphireTest {
|
||||
played a part in his <a href=journey"extra id="JourneyLink">journey</a>. HE ALSO DISCOVERED THE
|
||||
<A HREF="CAPS LOCK">KEY</a>. Later he got his <a href="quotes \'mixed\' up">mixed up</a>.
|
||||
</p>
|
||||
';
|
||||
|
||||
';
|
||||
|
||||
$expected = array (
|
||||
'/', 'home/', 'mother/', '$Journey', 'space travel', 'unquoted', 'single quote', '/father', 'attributes',
|
||||
'journey', 'CAPS LOCK', 'quotes \'mixed\' up'
|
||||
);
|
||||
|
||||
|
||||
$result = HTTP::getLinksIn($content);
|
||||
|
||||
// Results don't neccesarily come out in the order they are in the $content param.
|
||||
@ -41,7 +41,7 @@ class HTTPTest extends SapphireTest {
|
||||
|
||||
$this->assertTrue(is_array($result));
|
||||
$this->assertEquals($expected, $result, 'Test that all links within the content are found.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HTTP::setGetVar()}
|
||||
|
@ -11,7 +11,7 @@ class ArrayDataTest extends SapphireTest {
|
||||
$this->assertEquals("Varchar", get_class($arrayData->A));
|
||||
$this->assertEquals("ArrayData", get_class($arrayData->B));
|
||||
}
|
||||
|
||||
|
||||
public function testWrappingANonEmptyObjectWorks() {
|
||||
$object = new ArrayDataTest_NonEmptyObject();
|
||||
$this->assertTrue(is_object($object));
|
||||
|
@ -4,5 +4,5 @@
|
||||
*/
|
||||
|
||||
namespace silverstripe\test;
|
||||
|
||||
|
||||
class ClassB extends ClassA { }
|
||||
|
@ -55,7 +55,7 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
|
||||
$this->assertEquals(4, $resultDataObject->Count(),
|
||||
'Test if existing data is deleted before new data is added');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test import with manual column mapping
|
||||
|
@ -18,11 +18,11 @@ class FileFieldTest extends FunctionalTest {
|
||||
new FieldList()
|
||||
);
|
||||
$fileFieldValue = array(
|
||||
'name' => 'aCV.txt',
|
||||
'type' => 'application/octet-stream',
|
||||
'tmp_name' => '/private/var/tmp/phpzTQbqP',
|
||||
'error' => 0,
|
||||
'size' => 3471
|
||||
'name' => 'aCV.txt',
|
||||
'type' => 'application/octet-stream',
|
||||
'tmp_name' => '/private/var/tmp/phpzTQbqP',
|
||||
'error' => 0,
|
||||
'size' => 3471
|
||||
);
|
||||
$fileField->setValue($fileFieldValue);
|
||||
|
||||
@ -46,11 +46,11 @@ class FileFieldTest extends FunctionalTest {
|
||||
);
|
||||
// All fields are filled but for some reason an error occured when uploading the file => fails
|
||||
$fileFieldValue = array(
|
||||
'name' => 'aCV.txt',
|
||||
'type' => 'application/octet-stream',
|
||||
'tmp_name' => '/private/var/tmp/phpzTQbqP',
|
||||
'error' => 1,
|
||||
'size' => 3471
|
||||
'name' => 'aCV.txt',
|
||||
'type' => 'application/octet-stream',
|
||||
'tmp_name' => '/private/var/tmp/phpzTQbqP',
|
||||
'error' => 1,
|
||||
'size' => 3471
|
||||
);
|
||||
$fileField->setValue($fileFieldValue);
|
||||
|
||||
|
@ -368,7 +368,7 @@ class RequirementsTest extends SapphireTest {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function assertFileNotIncluded($backend, $type, $files) {
|
||||
$type = strtolower($type);
|
||||
switch ($type) {
|
||||
@ -412,4 +412,4 @@ class RequirementsTest extends SapphireTest {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* @subpackage tests
|
||||
*/
|
||||
|
||||
class UploadFieldTest extends FunctionalTest {
|
||||
class UploadFieldTest extends FunctionalTest {
|
||||
|
||||
static $fixture_file = 'UploadFieldTest.yml';
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
class SampleService
|
||||
{
|
||||
public $constructorVarOne;
|
||||
public $constructorVarOne;
|
||||
public $constructorVarTwo;
|
||||
|
||||
public function __construct($v1 = null, $v2 = null) {
|
||||
$this->constructorVarOne = $v1;
|
||||
$this->constructorVarTwo = $v2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
||||
'<input type="hidden" name="testfield" value="1" />' +
|
||||
'</div>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
$('#testfield').remove();
|
||||
@ -114,7 +114,7 @@
|
||||
'<input type="hidden" name="testfield" value="1" />' +
|
||||
'</div>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
$('#testfield').remove();
|
||||
@ -146,7 +146,7 @@
|
||||
'<input type="hidden" name="testfield" value="4,5" />' +
|
||||
'</div>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
$('#testfield').remove();
|
||||
@ -222,7 +222,7 @@
|
||||
'<input type="hidden" name="MyFormValue" value="foo" />' +
|
||||
'</form>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
$('#testfield').remove();
|
||||
@ -236,4 +236,4 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
||||
}(jQuery));
|
||||
|
@ -60,7 +60,6 @@ class ComponentSetTest_Player extends Member implements TestOnly {
|
||||
static $belongs_many_many = array(
|
||||
'Teams' => 'ComponentSetTest_Team'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
class ComponentSetTest_Team extends DataObject implements TestOnly {
|
||||
|
@ -624,11 +624,11 @@ class DataListTest extends SapphireTest {
|
||||
*/
|
||||
public function testExcludeOnFilter() {
|
||||
$list = DataObjectTest_TeamComment::get();
|
||||
$list = $list->filter('Comment', 'Phil is a unique guy, and comments on team2');
|
||||
$list = $list->filter('Comment', 'Phil is a unique guy, and comments on team2');
|
||||
$list = $list->exclude('Name', 'Bob');
|
||||
|
||||
$this->assertContains(
|
||||
'WHERE ("DataObjectTest_TeamComment"."Comment" = '
|
||||
'WHERE ("DataObjectTest_TeamComment"."Comment" = '
|
||||
. '\'Phil is a unique guy, and comments on team2\') '
|
||||
. 'AND (("DataObjectTest_TeamComment"."Name" != \'Bob\'))',
|
||||
$list->sql());
|
||||
|
@ -1125,7 +1125,6 @@ class DataObjectTest_Player extends Member implements TestOnly {
|
||||
static $belongs_many_many = array(
|
||||
'Teams' => 'DataObjectTest_Team'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
class DataObjectTest_Team extends DataObject implements TestOnly {
|
||||
|
@ -71,12 +71,12 @@ class MoneyTest extends SapphireTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Money object to the database, then re-read it to ensure it
|
||||
* is re-read properly.
|
||||
*/
|
||||
public function testGettingWrittenDataObject() {
|
||||
$local = i18n::get_locale();
|
||||
//make sure that the $ amount is not prefixed by US$, as it would be in non-US locale
|
||||
* Write a Money object to the database, then re-read it to ensure it
|
||||
* is re-read properly.
|
||||
*/
|
||||
public function testGettingWrittenDataObject() {
|
||||
$local = i18n::get_locale();
|
||||
//make sure that the $ amount is not prefixed by US$, as it would be in non-US locale
|
||||
i18n::set_locale('en_US');
|
||||
|
||||
$obj = new MoneyTest_DataObject();
|
||||
@ -99,8 +99,8 @@ class MoneyTest extends SapphireTest {
|
||||
"Money field not added to data object properly when read."
|
||||
);
|
||||
|
||||
i18n::set_locale($local);
|
||||
}
|
||||
i18n::set_locale($local);
|
||||
}
|
||||
|
||||
public function testToCurrency() {
|
||||
$USD = new Money();
|
||||
|
@ -43,11 +43,11 @@ class PaginatedListTest extends SapphireTest {
|
||||
public function testSetPaginationFromQuery() {
|
||||
$query = $this->getMock('SQLQuery');
|
||||
$query->expects($this->once())
|
||||
->method('getLimit')
|
||||
->will($this->returnValue(array('limit' => 15, 'start' => 30)));
|
||||
->method('getLimit')
|
||||
->will($this->returnValue(array('limit' => 15, 'start' => 30)));
|
||||
$query->expects($this->once())
|
||||
->method('unlimitedRowCount')
|
||||
->will($this->returnValue(100));
|
||||
->method('unlimitedRowCount')
|
||||
->will($this->returnValue(100));
|
||||
|
||||
$list = new PaginatedList(new ArrayList());
|
||||
$list->setPaginationFromQuery($query);
|
||||
|
@ -254,12 +254,12 @@ class VersionedTest extends SapphireTest {
|
||||
* Test that SQLQuery::queriedTables() applies the version-suffixes properly.
|
||||
*/
|
||||
public function testQueriedTables() {
|
||||
Versioned::reading_stage('Live');
|
||||
Versioned::reading_stage('Live');
|
||||
|
||||
$this->assertEquals(array(
|
||||
'VersionedTest_DataObject_Live',
|
||||
'VersionedTest_Subclass_Live',
|
||||
), DataObject::get('VersionedTest_Subclass')->dataQuery()->query()->queriedTables());
|
||||
$this->assertEquals(array(
|
||||
'VersionedTest_DataObject_Live',
|
||||
'VersionedTest_Subclass_Live',
|
||||
), DataObject::get('VersionedTest_Subclass')->dataQuery()->query()->queriedTables());
|
||||
}
|
||||
|
||||
public function testGetVersionWhenClassnameChanged() {
|
||||
|
18
tests/phpcs/tabs.xml
Normal file
18
tests/phpcs/tabs.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe.Tabs">
|
||||
<description>CodeSniffer ruleset for SilverStripe indentation conventions.</description>
|
||||
|
||||
<!-- exclude SCSS-generated CSS files -->
|
||||
<exclude-pattern>*/css/*</exclude-pattern>
|
||||
<exclude-pattern>css/*</exclude-pattern>
|
||||
|
||||
<!-- exclude thirdparty content -->
|
||||
<exclude-pattern>thirdparty/*</exclude-pattern>
|
||||
<exclude-pattern>*/jquery-changetracker/*</exclude-pattern>
|
||||
<exclude-pattern>parsers/HTML/BBCodeParser/*</exclude-pattern>
|
||||
|
||||
<!-- PHP-PEG generated file not intended for human consumption -->
|
||||
<exclude-pattern>*/SSTemplateParser.php$</exclude-pattern>
|
||||
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
|
||||
</ruleset>
|
||||
|
@ -41,40 +41,40 @@ class SearchContextTest extends SapphireTest {
|
||||
}
|
||||
|
||||
public function testPartialMatchUsedByDefaultWhenNotExplicitlySet() {
|
||||
$person = singleton('SearchContextTest_Person');
|
||||
$context = $person->getDefaultSearchContext();
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"Name" => new PartialMatchFilter("Name"),
|
||||
"HairColor" => new PartialMatchFilter("HairColor"),
|
||||
"EyeColor" => new PartialMatchFilter("EyeColor")
|
||||
),
|
||||
$context->getFilters()
|
||||
);
|
||||
$person = singleton('SearchContextTest_Person');
|
||||
$context = $person->getDefaultSearchContext();
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"Name" => new PartialMatchFilter("Name"),
|
||||
"HairColor" => new PartialMatchFilter("HairColor"),
|
||||
"EyeColor" => new PartialMatchFilter("EyeColor")
|
||||
),
|
||||
$context->getFilters()
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefaultFiltersDefinedWhenNotSetInDataObject() {
|
||||
$book = singleton('SearchContextTest_Book');
|
||||
$context = $book->getDefaultSearchContext();
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"Title" => new PartialMatchFilter("Title")
|
||||
),
|
||||
$context->getFilters()
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"Title" => new PartialMatchFilter("Title")
|
||||
),
|
||||
$context->getFilters()
|
||||
);
|
||||
}
|
||||
|
||||
public function testUserDefinedFiltersAppearInSearchContext() {
|
||||
$company = singleton('SearchContextTest_Company');
|
||||
$context = $company->getDefaultSearchContext();
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"Name" => new PartialMatchFilter("Name"),
|
||||
"Industry" => new PartialMatchFilter("Industry"),
|
||||
"AnnualProfit" => new PartialMatchFilter("AnnualProfit")
|
||||
"Industry" => new PartialMatchFilter("Industry"),
|
||||
"AnnualProfit" => new PartialMatchFilter("AnnualProfit")
|
||||
),
|
||||
$context->getFilters()
|
||||
);
|
||||
@ -87,8 +87,8 @@ class SearchContextTest extends SapphireTest {
|
||||
$this->assertEquals(
|
||||
new FieldList(
|
||||
new TextField("Name", 'Name'),
|
||||
new TextareaField("Industry", 'Industry'),
|
||||
new NumericField("AnnualProfit", 'The Almighty Annual Profit')
|
||||
new TextareaField("Industry", 'Industry'),
|
||||
new NumericField("AnnualProfit", 'The Almighty Annual Profit')
|
||||
),
|
||||
$context->getFields()
|
||||
);
|
||||
|
@ -52,47 +52,47 @@ class GroupTest extends FunctionalTest {
|
||||
public function testMemberGroupRelationForm() {
|
||||
Session::set('loggedInAs', $this->idFromFixture('GroupTest_Member', 'admin'));
|
||||
|
||||
$adminGroup = $this->objFromFixture('Group', 'admingroup');
|
||||
$parentGroup = $this->objFromFixture('Group', 'parentgroup');
|
||||
$childGroup = $this->objFromFixture('Group', 'childgroup');
|
||||
$adminGroup = $this->objFromFixture('Group', 'admingroup');
|
||||
$parentGroup = $this->objFromFixture('Group', 'parentgroup');
|
||||
$childGroup = $this->objFromFixture('Group', 'childgroup');
|
||||
|
||||
// Test single group relation through checkboxsetfield
|
||||
$form = new GroupTest_MemberForm($this, 'Form');
|
||||
$member = $this->objFromFixture('GroupTest_Member', 'admin');
|
||||
$form->loadDataFrom($member);
|
||||
$checkboxSetField = $form->Fields()->fieldByName('Groups');
|
||||
$checkboxSetField->setValue(array(
|
||||
$adminGroup->ID => $adminGroup->ID, // keep existing relation
|
||||
$parentGroup->ID => $parentGroup->ID, // add new relation
|
||||
));
|
||||
$form->saveInto($member);
|
||||
$updatedGroups = $member->Groups();
|
||||
// Test single group relation through checkboxsetfield
|
||||
$form = new GroupTest_MemberForm($this, 'Form');
|
||||
$member = $this->objFromFixture('GroupTest_Member', 'admin');
|
||||
$form->loadDataFrom($member);
|
||||
$checkboxSetField = $form->Fields()->fieldByName('Groups');
|
||||
$checkboxSetField->setValue(array(
|
||||
$adminGroup->ID => $adminGroup->ID, // keep existing relation
|
||||
$parentGroup->ID => $parentGroup->ID, // add new relation
|
||||
));
|
||||
$form->saveInto($member);
|
||||
$updatedGroups = $member->Groups();
|
||||
|
||||
$this->assertEquals(
|
||||
$this->assertEquals(
|
||||
array($adminGroup->ID, $parentGroup->ID),
|
||||
$updatedGroups->column(),
|
||||
"Adding a toplevel group works"
|
||||
);
|
||||
$updatedGroups->column(),
|
||||
"Adding a toplevel group works"
|
||||
);
|
||||
|
||||
// Test unsetting relationship
|
||||
$form->loadDataFrom($member);
|
||||
$checkboxSetField = $form->Fields()->fieldByName('Groups');
|
||||
$checkboxSetField->setValue(array(
|
||||
$adminGroup->ID => $adminGroup->ID, // keep existing relation
|
||||
//$parentGroup->ID => $parentGroup->ID, // remove previously set relation
|
||||
));
|
||||
$form->saveInto($member);
|
||||
$member->flushCache();
|
||||
$updatedGroups = $member->Groups();
|
||||
$this->assertEquals(
|
||||
// Test unsetting relationship
|
||||
$form->loadDataFrom($member);
|
||||
$checkboxSetField = $form->Fields()->fieldByName('Groups');
|
||||
$checkboxSetField->setValue(array(
|
||||
$adminGroup->ID => $adminGroup->ID, // keep existing relation
|
||||
//$parentGroup->ID => $parentGroup->ID, // remove previously set relation
|
||||
));
|
||||
$form->saveInto($member);
|
||||
$member->flushCache();
|
||||
$updatedGroups = $member->Groups();
|
||||
$this->assertEquals(
|
||||
array($adminGroup->ID),
|
||||
$updatedGroups->column(),
|
||||
"Removing a previously added toplevel group works"
|
||||
);
|
||||
$updatedGroups->column(),
|
||||
"Removing a previously added toplevel group works"
|
||||
);
|
||||
|
||||
// Test adding child group
|
||||
// Test adding child group
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testCollateAncestorIDs() {
|
||||
$parentGroup = $this->objFromFixture('Group', 'parentgroup');
|
||||
@ -139,37 +139,37 @@ class GroupTest extends FunctionalTest {
|
||||
}
|
||||
|
||||
class GroupTest_Member extends Member implements TestOnly {
|
||||
|
||||
public function getCMSFields() {
|
||||
$groups = DataObject::get('Group');
|
||||
$groupsMap = ($groups) ? $groups->map() : false;
|
||||
$fields = new FieldList(
|
||||
new HiddenField('ID', 'ID'),
|
||||
new CheckboxSetField(
|
||||
'Groups',
|
||||
'Groups',
|
||||
$groupsMap
|
||||
)
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
public function getCMSFields() {
|
||||
$groups = DataObject::get('Group');
|
||||
$groupsMap = ($groups) ? $groups->map() : false;
|
||||
$fields = new FieldList(
|
||||
new HiddenField('ID', 'ID'),
|
||||
new CheckboxSetField(
|
||||
'Groups',
|
||||
'Groups',
|
||||
$groupsMap
|
||||
)
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GroupTest_MemberForm extends Form {
|
||||
|
||||
public function __construct($controller, $name) {
|
||||
$fields = singleton('GroupTest_Member')->getCMSFields();
|
||||
$actions = new FieldList(
|
||||
new FormAction('doSave','save')
|
||||
);
|
||||
|
||||
parent::__construct($controller, $name, $fields, $actions);
|
||||
}
|
||||
|
||||
public function doSave($data, $form) {
|
||||
// done in testing methods
|
||||
}
|
||||
|
||||
|
||||
public function __construct($controller, $name) {
|
||||
$fields = singleton('GroupTest_Member')->getCMSFields();
|
||||
$actions = new FieldList(
|
||||
new FormAction('doSave','save')
|
||||
);
|
||||
|
||||
parent::__construct($controller, $name, $fields, $actions);
|
||||
}
|
||||
|
||||
public function doSave($data, $form) {
|
||||
// done in testing methods
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ class MemberTest extends FunctionalTest {
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
i18n::set_default_locale($this->local);
|
||||
}
|
||||
i18n::set_default_locale($this->local);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
@ -155,9 +155,9 @@ class ViewableDataTest_Castable extends ViewableData {
|
||||
return $this->unsafeXML();
|
||||
}
|
||||
|
||||
public function forTemplate() {
|
||||
return 'castable';
|
||||
}
|
||||
public function forTemplate() {
|
||||
return 'castable';
|
||||
}
|
||||
}
|
||||
|
||||
class ViewableDataTest_RequiresCasting extends ViewableData {
|
||||
|
@ -65,7 +65,7 @@ class ArrayData extends ViewableData {
|
||||
return new ArrayData($value);
|
||||
} elseif (ArrayLib::is_associative($value)) {
|
||||
return new ArrayData($value);
|
||||
} else {
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class Requirements {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function get_combined_files_enabled() {
|
||||
return self::backend()->get_combined_files_enabled();
|
||||
return self::backend()->get_combined_files_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -656,7 +656,7 @@ class Requirements_Backend {
|
||||
$jsRequirements = '';
|
||||
|
||||
// Combine files - updates $this->javascript and $this->css
|
||||
$this->process_combined_files();
|
||||
$this->process_combined_files();
|
||||
|
||||
foreach(array_diff_key($this->javascript,$this->blocked) as $file => $dummy) {
|
||||
$path = $this->path_for_file($file);
|
||||
@ -1022,9 +1022,9 @@ class Requirements_Backend {
|
||||
// file exists, check modification date of every contained file
|
||||
$srcLastMod = 0;
|
||||
foreach($fileList as $file) {
|
||||
if(file_exists($base . $file)) {
|
||||
$srcLastMod = max(filemtime($base . $file), $srcLastMod);
|
||||
}
|
||||
if(file_exists($base . $file)) {
|
||||
$srcLastMod = max(filemtime($base . $file), $srcLastMod);
|
||||
}
|
||||
}
|
||||
$refresh = $srcLastMod > filemtime($combinedFilePath);
|
||||
} else {
|
||||
@ -1070,9 +1070,9 @@ class Requirements_Backend {
|
||||
// method repeatedly - it will behave different on the second call!
|
||||
$this->javascript = $newJSRequirements;
|
||||
$this->css = $newCSSRequirements;
|
||||
}
|
||||
|
||||
public function get_custom_scripts() {
|
||||
}
|
||||
|
||||
public function get_custom_scripts() {
|
||||
$requirements = "";
|
||||
|
||||
if($this->customScript) {
|
||||
|
@ -453,7 +453,7 @@ class SSTemplateParser extends Parser {
|
||||
function Require_Call(&$res, $sub) {
|
||||
$res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!*
|
||||
|
||||
@ -617,7 +617,7 @@ class SSTemplateParser extends Parser {
|
||||
function OldTTag_OldTPart(&$res, $sub) {
|
||||
$res['php'] = $sub['php'];
|
||||
}
|
||||
|
||||
|
||||
/*!*
|
||||
|
||||
# This is the old <% sprintf(_t()) %> tag
|
||||
|
@ -664,10 +664,10 @@ class SSViewer {
|
||||
}
|
||||
|
||||
if(!$this->chosenTemplates) {
|
||||
$templateList = (is_array($templateList)) ? $templateList : array($templateList);
|
||||
|
||||
user_error("None of these templates can be found in theme '"
|
||||
. self::current_theme() . "': ". implode(".ss, ", $templateList) . ".ss", E_USER_WARNING);
|
||||
$templateList = (is_array($templateList)) ? $templateList : array($templateList);
|
||||
|
||||
user_error("None of these templates can be found in theme '"
|
||||
. self::current_theme() . "': ". implode(".ss, ", $templateList) . ".ss", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,7 +717,7 @@ class SSViewer {
|
||||
protected static $options = array(
|
||||
'rewriteHashlinks' => true,
|
||||
);
|
||||
|
||||
|
||||
protected static $topLevel = array();
|
||||
|
||||
public static function topLevel() {
|
||||
|
Loading…
Reference in New Issue
Block a user