diff --git a/ORM/Connect/MySQLiConnector.php b/ORM/Connect/MySQLiConnector.php index 38fa654e0..2be7a74a6 100644 --- a/ORM/Connect/MySQLiConnector.php +++ b/ORM/Connect/MySQLiConnector.php @@ -102,7 +102,7 @@ class MySQLiConnector extends DBConnector { } public function __destruct() { - if ($this->dbConn) { + if (is_resource($this->dbConn)) { mysqli_close($this->dbConn); $this->dbConn = null; } diff --git a/ORM/FieldType/DBField.php b/ORM/FieldType/DBField.php index 0d47866b8..43ff6e888 100644 --- a/ORM/FieldType/DBField.php +++ b/ORM/FieldType/DBField.php @@ -256,19 +256,19 @@ abstract class DBField extends ViewableData { } public function HTMLATT() { - return Convert::raw2htmlatt($this->value); + return Convert::raw2htmlatt($this->RAW()); } public function URLATT() { - return urlencode($this->value); + return urlencode($this->RAW()); } public function RAWURLATT() { - return rawurlencode($this->value); + return rawurlencode($this->RAW()); } public function ATT() { - return Convert::raw2att($this->value); + return Convert::raw2att($this->RAW()); } public function RAW() { @@ -276,7 +276,7 @@ abstract class DBField extends ViewableData { } public function JS() { - return Convert::raw2js($this->value); + return Convert::raw2js($this->RAW()); } /** @@ -284,15 +284,15 @@ abstract class DBField extends ViewableData { * @return string */ public function JSON() { - return Convert::raw2json($this->value); + return Convert::raw2json($this->RAW()); } public function HTML(){ - return Convert::raw2xml($this->value); + return Convert::raw2xml($this->RAW()); } public function XML(){ - return Convert::raw2xml($this->value); + return Convert::raw2xml($this->RAW()); } /** diff --git a/ORM/FieldType/DBHTMLText.php b/ORM/FieldType/DBHTMLText.php index 528669803..73efceb1f 100644 --- a/ORM/FieldType/DBHTMLText.php +++ b/ORM/FieldType/DBHTMLText.php @@ -111,7 +111,7 @@ class DBHTMLText extends DBText { // Catch warnings thrown by loadHTML and turn them into a failure boolean rather than a SilverStripe error set_error_handler(create_function('$no, $str', 'throw new Exception("HTML Parse Error: ".$str);'), E_ALL); // Nonbreaking spaces get converted into weird characters, so strip them - $value = str_replace(' ', ' ', $this->value); + $value = str_replace(' ', ' ', $this->RAW()); try { $res = $doc->loadHTML('' . $value); } @@ -186,6 +186,15 @@ class DBHTMLText extends DBText { return $this->Summary(); } + public function RAW() { + if ($this->processShortcodes) { + return ShortcodeParser::get_active()->parse($this->value); + } + else { + return $this->value; + } + } + /** * Return the value of the field with relative links converted to absolute urls (with placeholders parsed). * @return string @@ -195,12 +204,7 @@ class DBHTMLText extends DBText { } public function forTemplate() { - if ($this->processShortcodes) { - return ShortcodeParser::get_active()->parse($this->value); - } - else { - return $this->value; - } + return $this->RAW(); } public function prepValueForDB($value) { @@ -248,14 +252,16 @@ class DBHTMLText extends DBText { return false; } + $value = $this->RAW(); + // If it's got a content tag - if(preg_match('/<(img|embed|object|iframe|meta|source|link)[^>]*>/i', $this->value)) { + if(preg_match('/<(img|embed|object|iframe|meta|source|link)[^>]*>/i', $value)) { return true; } // If it's just one or two tags on its own (and not the above) it's empty. // This might be

or

or whatever. - if(preg_match('/^[\\s]*(<[^>]+>[\\s]*){1,2}$/', $this->value)) { + if(preg_match('/^[\\s]*(<[^>]+>[\\s]*){1,2}$/', $value)) { return false; } diff --git a/ORM/FieldType/DBHTMLVarchar.php b/ORM/FieldType/DBHTMLVarchar.php index 131429930..f01f357ee 100644 --- a/ORM/FieldType/DBHTMLVarchar.php +++ b/ORM/FieldType/DBHTMLVarchar.php @@ -28,16 +28,21 @@ class DBHTMLVarchar extends DBVarchar { } public function forTemplate() { + return $this->RAW(); + } + + public function RAW() { if ($this->processShortcodes) { return ShortcodeParser::get_active()->parse($this->value); } else { return $this->value; } + } public function exists() { - return parent::exists() && $this->value != '

'; + return parent::exists() && $this->RAW() != '

'; } public function scaffoldFormField($title = null, $params = null) { diff --git a/ORM/FieldType/DBString.php b/ORM/FieldType/DBString.php index fd6018960..a28e1fcff 100644 --- a/ORM/FieldType/DBString.php +++ b/ORM/FieldType/DBString.php @@ -88,9 +88,10 @@ abstract class DBString extends DBField { * @see core/model/fieldtypes/DBField#exists() */ public function exists() { - return $this->getValue() // All truthy values exist - || (is_string($this->getValue()) && strlen($this->getValue())) // non-empty strings exist ('0' but not (int)0) - || (!$this->getNullifyEmpty() && $this->getValue() === ''); // Remove this stupid exemption in 4.0 + $value = $this->RAW(); + return $value // All truthy values exist + || (is_string($value) && strlen($value)) // non-empty strings exist ('0' but not (int)0) + || (!$this->getNullifyEmpty() && $value === ''); // Remove this stupid exemption in 4.0 } /** @@ -122,7 +123,7 @@ abstract class DBString extends DBField { * @return string */ public function LimitCharacters($limit = 20, $add = '...') { - $value = trim($this->value); + $value = trim($this->RAW()); if($this->stat('escape_type') == 'xml') { $value = strip_tags($value); $value = html_entity_decode($value, ENT_COMPAT, 'UTF-8'); @@ -146,13 +147,13 @@ abstract class DBString extends DBField { */ public function LimitCharactersToClosestWord($limit = 20, $add = '...') { // Strip HTML tags if they exist in the field - $this->value = strip_tags($this->value); + $value = strip_tags($this->RAW()); // Determine if value exceeds limit before limiting characters - $exceedsLimit = mb_strlen($this->value) > $limit; + $exceedsLimit = mb_strlen($value) > $limit; // Limit to character limit - $value = $this->LimitCharacters($limit, ''); + $value = DBField::create_field(get_class($this), $value)->LimitCharacters($limit, ''); // If value exceeds limit, strip punctuation off the end to the last space and apply ellipsis if($exceedsLimit) { @@ -178,11 +179,11 @@ abstract class DBString extends DBField { * @return string */ public function LimitWordCount($numWords = 26, $add = '...') { - $this->value = trim(Convert::xml2raw($this->value)); - $ret = explode(' ', $this->value, $numWords + 1); + $value = trim(Convert::xml2raw($this->RAW())); + $ret = explode(' ', $value, $numWords + 1); if(count($ret) <= $numWords - 1) { - $ret = $this->value; + $ret = $value; } else { array_pop($ret); $ret = implode(' ', $ret) . $add; @@ -213,7 +214,7 @@ abstract class DBString extends DBField { * @return string */ public function LowerCase() { - return mb_strtolower($this->value); + return mb_strtolower($this->RAW()); } /** @@ -221,7 +222,7 @@ abstract class DBString extends DBField { * @return string */ public function UpperCase() { - return mb_strtoupper($this->value); + return mb_strtoupper($this->RAW()); } /** @@ -230,6 +231,6 @@ abstract class DBString extends DBField { * @return string */ public function NoHTML() { - return strip_tags($this->value); + return strip_tags($this->RAW()); } } diff --git a/ORM/FieldType/DBText.php b/ORM/FieldType/DBText.php index d753590bc..bb79fecdb 100644 --- a/ORM/FieldType/DBText.php +++ b/ORM/FieldType/DBText.php @@ -71,7 +71,7 @@ class DBText extends DBString { * @return string */ public function AbsoluteLinks() { - return HTTP::absoluteURLs($this->value); + return HTTP::absoluteURLs($this->RAW()); } /** @@ -86,7 +86,7 @@ class DBText extends DBString { } $output = array(); - $data = trim(Convert::xml2raw($this->value)); + $data = trim(Convert::xml2raw($this->RAW())); $sentences = explode('.', $data); if ($sentCount == 0) return ''; @@ -106,7 +106,7 @@ class DBText extends DBString { * Caution: Not XML/HTML-safe - does not respect closing tags. */ public function FirstSentence() { - $paragraph = Convert::xml2raw( $this->value ); + $paragraph = Convert::xml2raw( $this->RAW() ); if( !$paragraph ) return ""; $words = preg_split('/\s+/', $paragraph); @@ -127,7 +127,7 @@ class DBText extends DBString { public function Summary($maxWords = 50) { // get first sentence? // this needs to be more robust - $value = Convert::xml2raw( $this->value /*, true*/ ); + $value = Convert::xml2raw( $this->RAW() /*, true*/ ); if(!$value) return ''; // grab the first paragraph, or, failing that, the whole content @@ -169,7 +169,7 @@ class DBText extends DBString { // get first sentence? // this needs to be more robust - $data = $plain ? Convert::xml2raw($this->value, true) : $this->value; + $data = $plain ? Convert::xml2raw($this->RAW(), true) : $this->RAW(); if(!$data) return ''; @@ -209,8 +209,9 @@ class DBText extends DBString { public function FirstParagraph($plain = 1) { // get first sentence? // this needs to be more robust + $value = $this->RAW(); if($plain && $plain != 'html') { - $data = Convert::xml2raw($this->value); + $data = Convert::xml2raw($value); if(!$data) return ""; // grab the first paragraph, or, failing that, the whole content @@ -219,12 +220,12 @@ class DBText extends DBString { return $data; } else { - if(strpos($this->value, "

") === false) return $this->value; + if(strpos($value, "

") === false) return $value; - $data = substr($this->value, 0, strpos($this->value, "

") + 4); + $data = substr($value, 0, strpos($value, "

") + 4); - if(strlen($data) < 20 && strpos($this->value, "

", strlen($data))) { - $data = substr($this->value, 0, strpos( $this->value, "

", strlen($data)) + 4 ); + if(strlen($data) < 20 && strpos($value, "

", strlen($data))) { + $data = substr($value, 0, strpos( $value, "

", strlen($data)) + 4 ); } return $data; @@ -253,7 +254,7 @@ class DBText extends DBString { } // Remove HTML tags so we don't have to deal with matching tags - $text = $striphtml ? $this->NoHTML() : $this->value; + $text = $striphtml ? $this->NoHTML() : $this->RAW(); // Find the search string $position = (int) stripos($text, $string); @@ -285,7 +286,7 @@ class DBText extends DBString { $summary = trim($summary); if($position > 0) $summary = $prefix . $summary; - if(strlen($this->value) > ($characters + $position)) $summary = $summary . $suffix; + if(strlen($this->RAW()) > ($characters + $position)) $summary = $summary . $suffix; return $summary; } @@ -299,14 +300,14 @@ class DBText extends DBString { */ public function Parse($parser = "TextParser") { if($parser == "TextParser" || is_subclass_of($parser, "TextParser")) { - $obj = new $parser($this->value); + $obj = new $parser($this->RAW()); return $obj->parse(); } else { // Fallback to using raw2xml and show a warning // TODO Don't kill script execution, we can continue without losing complete control of the app user_error("Couldn't find an appropriate TextParser sub-class to create (Looked for '$parser')." . "Make sure it sub-classes TextParser and that you've done ?flush=1.", E_USER_WARNING); - return Convert::raw2xml($this->value); + return Convert::raw2xml($this->RAW()); } } diff --git a/ORM/FieldType/DBVarchar.php b/ORM/FieldType/DBVarchar.php index ef8645629..a0193fe8e 100644 --- a/ORM/FieldType/DBVarchar.php +++ b/ORM/FieldType/DBVarchar.php @@ -80,15 +80,19 @@ class DBVarchar extends DBString { * Return the first letter of the string followed by a . */ public function Initial() { - if($this->exists()) return $this->value[0] . '.'; + if($this->exists()) { + $value = $this->RAW(); + return $value[0] . '.'; + } } /** * Ensure that the given value is an absolute URL. */ public function URL() { - if(preg_match('#^[a-zA-Z]+://#', $this->value)) return $this->value; - else return "http://" . $this->value; + $value = $this->RAW(); + if(preg_match('#^[a-zA-Z]+://#', $value)) return $value; + else return "http://" . $value; } /** @@ -96,7 +100,7 @@ class DBVarchar extends DBString { * @return string */ public function RTF() { - return str_replace("\n", '\par ', $this->value); + return str_replace("\n", '\par ', $this->RAW()); } /** diff --git a/Security/MemberLoginForm.php b/Security/MemberLoginForm.php index 1dc376509..121930d86 100644 --- a/Security/MemberLoginForm.php +++ b/Security/MemberLoginForm.php @@ -129,7 +129,7 @@ class MemberLoginForm extends LoginForm { FormAction::create('dologin', _t('Member.BUTTONLOGIN', "Log in")), LiteralField::create( 'forgotPassword', - '

' + '

' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '

' ) ); diff --git a/Security/Permission.php b/Security/Permission.php index 48a7b9e4b..652feb8c9 100644 --- a/Security/Permission.php +++ b/Security/Permission.php @@ -201,10 +201,9 @@ class Permission extends DataObject implements TemplateGlobalProvider { } } } - elseif (substr($permCode, 0, 11) === 'CMS_ACCESS_') { + elseif (substr($permCode, 0, 11) === 'CMS_ACCESS_' && !in_array('CMS_ACCESS_LeftAndMain', $code)) { //cms_access_leftandmain means access to all CMS areas $code[] = 'CMS_ACCESS_LeftAndMain'; - break; } } diff --git a/Security/Security.php b/Security/Security.php index 4afb6e9db..100495da5 100644 --- a/Security/Security.php +++ b/Security/Security.php @@ -155,6 +155,15 @@ class Security extends Controller implements TemplateGlobalProvider { */ private static $logout_url = "Security/logout"; + /** + * The default lost password URL + * + * @config + * + * @var string + */ + private static $lost_password_url = "Security/lostpassword"; + /** * Get location of word list file * @@ -1159,7 +1168,7 @@ class Security extends Controller implements TemplateGlobalProvider { * @return string */ public static function login_url() { - return self::config()->login_url; + return Controller::join_links(Director::baseURL(), self::config()->login_url); } @@ -1171,9 +1180,19 @@ class Security extends Controller implements TemplateGlobalProvider { * @return string */ public static function logout_url() { - return self::config()->logout_url; + return Controller::join_links(Director::baseURL(), self::config()->logout_url); } + /** + * Get the URL of the logout page. + * + * To update the logout url use the "Security.logout_url" config setting. + * + * @return string + */ + public static function lost_password_url() { + return Controller::join_links(Director::baseURL(), self::config()->lost_password_url); + } /** * Defines global accessible templates variables. @@ -1184,6 +1203,7 @@ class Security extends Controller implements TemplateGlobalProvider { return array( "LoginURL" => "login_url", "LogoutURL" => "logout_url", + "LostPasswordURL" => "lost_password_url", ); } diff --git a/docs/en/02_Developer_Guides/00_Model/02_Relations.md b/docs/en/02_Developer_Guides/00_Model/02_Relations.md index b3cb2bd1c..83ddbbae3 100644 --- a/docs/en/02_Developer_Guides/00_Model/02_Relations.md +++ b/docs/en/02_Developer_Guides/00_Model/02_Relations.md @@ -147,7 +147,7 @@ you will get an instance of [api:HasManyList] rather than the object. echo $player->FirstName; } -To specify multiple $has_manys to the same object you can use dot notation to distinguish them like below: +To specify multiple `$has_many` to the same object you can use dot notation to distinguish them like below: :::php removeByName(array('ManagerID', 'CleanerID')); + return $fields; + } + ## belongs_to Defines a 1-to-1 relationship with another object, which declares the other end of the relationship with a -corresponding $has_one. A single database column named `ID` will be created in the object with the +corresponding `$has_one`. A single database column named `ID` will be created in the object with the `$has_one`, but the $belongs_to by itself will not create a database field. This field will hold the ID of the object declaring the `$belongs_to`. -Similarly with $has_many, dot notation can be used to explicitly specify the `$has_one` which refers to this relation. +Similarly with `$has_many`, dot notation can be used to explicitly specify the `$has_one` which refers to this relation. This is not mandatory unless the relationship would be otherwise ambiguous. :::php diff --git a/docs/en/02_Developer_Guides/14_Files/02_Images.md b/docs/en/02_Developer_Guides/14_Files/02_Images.md index ead5221b5..ccccb5b51 100644 --- a/docs/en/02_Developer_Guides/14_Files/02_Images.md +++ b/docs/en/02_Developer_Guides/14_Files/02_Images.md @@ -75,6 +75,19 @@ Image methods are chainable. Example: :::ss +### Padded Image Resize + +The Pad method allows you to resize an image with existing ratio and will +pad any surplus space. You can specify the color of the padding using a hex code such as FFFFFF or 000000. + +You can also specify a level of transparency to apply to the padding color in a fourth param. This will only effect +png images. + + :::php + $Image.Pad(80, 80, FFFFFF, 50) // white padding with 50% transparency + $Image.Pad(80, 80, FFFFFF, 100) // white padding with 100% transparency + $Image.Pad(80, 80, FFFFFF) // white padding with no transparency + ### Manipulating images in PHP The image manipulation functions can be used in your code with the same names, example: `$image->Fill(150,150)`. diff --git a/filesystem/ImagickBackend.php b/filesystem/ImagickBackend.php index 522030f39..efe787fa0 100644 --- a/filesystem/ImagickBackend.php +++ b/filesystem/ImagickBackend.php @@ -150,19 +150,61 @@ class ImagickBackend extends Imagick implements Image_Backend { return $this->resize( $scale * $geometry["width"], $height ); } - public function paddedResize($width, $height, $backgroundColor = "FFFFFF") { + /** + * paddedResize + * + * @param int $width + * @param int $height + * @param int $transparencyPercent + * @return Image_Backend + */ + public function paddedResize($width, $height, $backgroundColor = "FFFFFF", $transparencyPercent = 0) { if(!$this->valid()) { return null; } + + //keep the % within bounds of 0-100 + $transparencyPercent = min(100, max(0, $transparencyPercent)); $new = $this->resizeRatio($width, $height); - $new->setImageBackgroundColor("#".$backgroundColor); + if($transparencyPercent) { + $alphaHex = $this->calculateAlphaHex($transparencyPercent); + $new->setImageBackgroundColor("#{$backgroundColor}{$alphaHex}"); + } else { + $new->setImageBackgroundColor("#{$backgroundColor}"); + } $w = $new->getImageWidth(); $h = $new->getImageHeight(); $new->extentImage($width,$height,($w-$width)/2,($h-$height)/2); return $new; } + /** + * Convert a percentage (or 'true') to a two char hex code to signifiy the level of an alpha channel + * + * @param $percent + * @return string + */ + public function calculateAlphaHex($percent) { + if($percent > 100) { + $percent = 100; + } + // unlike GD, this uses 255 instead of 127, and is reversed. Lower = more transparent + $alphaHex = dechex(255 - floor(255 * bcdiv($percent, 100, 2))); + if(strlen($alphaHex) == 1) { + $alphaHex = '0' .$alphaHex; + } + return $alphaHex; + } + + + /** + * croppedResize + * + * @param int $width + * @param int $height + * @return Image_Backend + */ public function croppedResize($width, $height) { if(!$this->valid()) { return null; diff --git a/forms/CheckboxSetField.php b/forms/CheckboxSetField.php index 3ff403041..f07a7abdd 100644 --- a/forms/CheckboxSetField.php +++ b/forms/CheckboxSetField.php @@ -53,9 +53,7 @@ class CheckboxSetField extends MultiSelectField { 'Options' => $this->getOptions() )); - return $this->customise($properties)->renderWith( - $this->getTemplates() - ); + return FormField::Field($properties); } /** diff --git a/forms/ListboxField.php b/forms/ListboxField.php index 8bd9cd64d..abe56e98d 100644 --- a/forms/ListboxField.php +++ b/forms/ListboxField.php @@ -65,11 +65,10 @@ class ListboxField extends MultiSelectField { */ public function Field($properties = array()) { $properties = array_merge($properties, array( - 'Options' => $this->getOptions() + 'Options' => $this->getOptions(), )); - return $this - ->customise($properties) - ->renderWith($this->getTemplates()); + + return FormField::Field($properties); } /** diff --git a/forms/OptionsetField.php b/forms/OptionsetField.php index f3790e8af..aa46b3ecd 100644 --- a/forms/OptionsetField.php +++ b/forms/OptionsetField.php @@ -121,9 +121,7 @@ class OptionsetField extends SingleSelectField { 'Options' => new ArrayList($options) )); - return $this->customise($properties)->renderWith( - $this->getTemplates() - ); + return FormField::Field($properties); } /** diff --git a/forms/TreeDropdownField.php b/forms/TreeDropdownField.php index 9d5c3985b..673d3c6c6 100644 --- a/forms/TreeDropdownField.php +++ b/forms/TreeDropdownField.php @@ -261,7 +261,7 @@ class TreeDropdownField extends FormField { ) ); - return $this->customise($properties)->renderWith('TreeDropdownField'); + return parent::Field($properties); } public function extraClass() { diff --git a/forms/TreeMultiselectField.php b/forms/TreeMultiselectField.php index 6accad2cc..1c5c9a4e1 100644 --- a/forms/TreeMultiselectField.php +++ b/forms/TreeMultiselectField.php @@ -145,7 +145,7 @@ class TreeMultiselectField extends TreeDropdownField { 'Value' => $value ) ); - return $this->customise($properties)->renderWith('TreeDropdownField'); + return FormField::Field($properties); } /** diff --git a/forms/UploadField.php b/forms/UploadField.php index b7b76de9c..b19595973 100644 --- a/forms/UploadField.php +++ b/forms/UploadField.php @@ -1016,11 +1016,11 @@ class UploadField extends FileField { } $mergedConfig = array_merge($config, $this->ufConfig); - return $this->customise(array( + return parent::Field(array( 'configString' => str_replace('"', """, Convert::raw2json($mergedConfig)), 'config' => new ArrayData($mergedConfig), 'multiple' => $allowedMaxFileNumber !== 1 - ))->renderWith($this->getTemplates()); + )); } /** diff --git a/parsers/ShortcodeParser.php b/parsers/ShortcodeParser.php index 354d34c36..2ab935089 100644 --- a/parsers/ShortcodeParser.php +++ b/parsers/ShortcodeParser.php @@ -270,11 +270,18 @@ class ShortcodeParser extends Object { preg_match_all(static::attrrx(), $match['attrs'][0], $attrmatches, PREG_SET_ORDER); foreach ($attrmatches as $attr) { - list($whole, $name, $value) = array_values(array_filter($attr, function($attrPart) { - return $attrPart !== ''; - })); + $name = ''; + $value = ''; + $parts = array_values(array_filter($attr)); + //the first element in the array is the complete delcaration (`id=1`) - we don't need this + array_shift($parts); + + //the next two parts are what we care about (id and 1 from `id=1`) + $name = array_shift($parts) ?: $name; + $value = array_shift($parts) ?: $value; + $attrs[$name] = $value; - } + } } // And store the indexes, tag details, etc @@ -553,6 +560,9 @@ class ShortcodeParser extends Object { // If no content, don't try and parse it if (!trim($content)) return $content; + // If no shortcode tag, don't try and parse it + if (strpos($content, '[') === false) return $content; + // First we operate in text mode, replacing any shortcodes with marker elements so that later we can // use a proper DOM list($content, $tags) = $this->replaceElementTagsWithMarkers($content); diff --git a/tests/core/manifest/ConfigStaticManifestTest/ConfigStaticManifestTestClassKeyword.php b/tests/core/manifest/ConfigStaticManifestTest/ConfigStaticManifestTestClassKeyword.php new file mode 100644 index 000000000..cfd8e740b --- /dev/null +++ b/tests/core/manifest/ConfigStaticManifestTest/ConfigStaticManifestTestClassKeyword.php @@ -0,0 +1,11 @@ +inst = Injector::inst()->get(static::class); + } + +} diff --git a/tests/model/DBHTMLTextTest.php b/tests/model/DBHTMLTextTest.php index aa2617aa8..f1f53dddf 100644 --- a/tests/model/DBHTMLTextTest.php +++ b/tests/model/DBHTMLTextTest.php @@ -199,4 +199,126 @@ class DBHTMLTextTest extends SapphireTest { 'Removes any elements not in whitelist including text elements' ); } + + public function testShortCodeParsedInRAW() { + $parser = ShortcodeParser::get('HTMLTextTest'); + $parser->register('shortcode', function($arguments, $content, $parser, $tagName, $extra) { + return 'replaced'; + }); + ShortcodeParser::set_active('HTMLTextTest'); + /** @var DBHTMLText $field */ + $field = DBField::create_field('HTMLText', '

[shortcode]

'); + $this->assertEquals('

replaced

', $field->RAW()); + $this->assertEquals('

replaced

', (string)$field); + + $field->setOptions(array( + 'shortcodes' => false, + )); + + $this->assertEquals('

[shortcode]

', $field->RAW()); + $this->assertEquals('

[shortcode]

', (string)$field); + + + ShortcodeParser::set_active('default'); + } + + public function testShortCodeParsedInTemplateHelpers() { + $parser = ShortcodeParser::get('HTMLTextTest'); + $parser->register('shortcode', function($arguments, $content, $parser, $tagName, $extra) { + return 'Replaced short code with this. home'; + }); + ShortcodeParser::set_active('HTMLTextTest'); + /** @var DBHTMLText $field */ + $field = DBField::create_field('HTMLText', '

[shortcode]

'); + + $this->assertEquals( + '<p>Replaced short code with this. <a href="home">home</a></p>', + $field->HTMLATT() + ); + $this->assertEquals( + '%3Cp%3EReplaced+short+code+with+this.+%3Ca+href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', + $field->URLATT() + ); + $this->assertEquals( + '%3Cp%3EReplaced%20short%20code%20with%20this.%20%3Ca%20href%3D%22home%22%3Ehome%3C%2Fa%3E%3C%2Fp%3E', + $field->RAWURLATT() + ); + $this->assertEquals( + '<p>Replaced short code with this. <a href="home">home</a></p>', + $field->ATT() + ); + $this->assertEquals( + '

Replaced short code with this. home

', + $field->RAW() + ); + $this->assertEquals( + '\x3cp\x3eReplaced short code with this. \x3ca href=\"home\"\x3ehome\x3c/a\x3e\x3c/p\x3e', + $field->JS() + ); + $this->assertEquals( + '<p>Replaced short code with this. <a href="home">home</a></p>', + $field->HTML() + ); + $this->assertEquals( + '<p>Replaced short code with this. <a href="home">home</a></p>', + $field->XML() + ); + $this->assertEquals( + 'Repl...', + $field->LimitCharacters(4, '...') + ); + $this->assertEquals( + 'Replaced...', + $field->LimitCharactersToClosestWord(10, '...') + ); + $this->assertEquals( + 'Replaced...', + $field->LimitWordCount(1, '...') + ); + $this->assertEquals( + '

replaced short code with this. home

', + $field->LowerCase() + ); + $this->assertEquals( + '

REPLACED SHORT CODE WITH THIS. HOME

', + $field->UpperCase() + ); + $this->assertEquals( + 'Replaced short code with this. home', + $field->NoHTML() + ); + Config::nest(); + Config::inst()->update('Director', 'alternate_base_url', 'http://example.com/'); + $this->assertEquals( + '

Replaced short code with this. home

', + $field->AbsoluteLinks() + ); + Config::unnest(); + $this->assertEquals( + 'Replaced short code with this.', + $field->LimitSentences(1) + ); + $this->assertEquals( + 'Replaced short code with this.', + $field->FirstSentence() + ); + $this->assertEquals( + 'Replaced short...', + $field->Summary(2) + ); + $this->assertEquals( + 'Replaced short code with...', + $field->BigSummary(4) + ); + $this->assertEquals( + 'Replaced short code with this. home[home]', + $field->FirstParagraph() + ); + $this->assertEquals( + 'Replaced short code with this. home', + $field->ContextSummary(500, 'short code') + ); + + ShortcodeParser::set_active('default'); + } } diff --git a/tests/parsers/ShortcodeParserTest.php b/tests/parsers/ShortcodeParserTest.php index 8a64bfc5e..85dcaa3b4 100644 --- a/tests/parsers/ShortcodeParserTest.php +++ b/tests/parsers/ShortcodeParserTest.php @@ -15,6 +15,12 @@ class ShortcodeParserTest extends SapphireTest { parent::setUp(); } + public function tearDown() { + ShortcodeParser::get('test')->unregister('test_shortcode'); + + parent::tearDown(); + } + /** * Tests that valid short codes that have not been registered are not replaced. */ @@ -218,6 +224,14 @@ class ShortcodeParserTest extends SapphireTest { ); } + public function testFalseyArguments() { + $this->parser->parse('

[test_shortcode falsey=0]'); + + $this->assertEquals(array( + 'falsey' => '', + ), $this->arguments); + } + public function testNumericShortcodes() { $this->assertEqualsIgnoringWhitespace( '[2]', @@ -240,6 +254,8 @@ class ShortcodeParserTest extends SapphireTest { '', $this->parser->parse('') ); + + $this->parser->unregister('2'); } public function testExtraContext() { @@ -250,6 +266,18 @@ class ShortcodeParserTest extends SapphireTest { $this->assertEquals($this->extra['element']->tagName, 'a'); } + public function testNoParseAttemptIfNoCode() { + $stub = $this->getMock('ShortcodeParser', array('replaceElementTagsWithMarkers')); + $stub->register('test', function() { + return ''; + }); + + $stub->expects($this->never()) + ->method('replaceElementTagsWithMarkers')->will($this->returnValue(array('', ''))); + + $stub->parse('

test

'); + } + // ----------------------------------------------------------------------------------------------------------------- /** diff --git a/tests/security/PermissionTest.php b/tests/security/PermissionTest.php index 63eb0df7e..d40712681 100644 --- a/tests/security/PermissionTest.php +++ b/tests/security/PermissionTest.php @@ -31,6 +31,8 @@ class PermissionTest extends SapphireTest { $members = Member::get()->byIDs($this->allFixtureIDs('SilverStripe\\Security\\Member')); foreach ($members as $member) { $this->assertTrue(Permission::checkMember($member, 'CMS_ACCESS')); + $this->assertTrue(Permission::checkMember($member, array('CMS_ACCESS', 'CMS_ACCESS_Security'))); + $this->assertTrue(Permission::checkMember($member, array('CMS_ACCESS_Security', 'CMS_ACCESS'))); } $member = new Member(); @@ -41,6 +43,8 @@ class PermissionTest extends SapphireTest { )); $member->write(); $this->assertFalse(Permission::checkMember($member, 'CMS_ACCESS')); + $this->assertFalse(Permission::checkMember($member, array('CMS_ACCESS', 'CMS_ACCESS_Security'))); + $this->assertFalse(Permission::checkMember($member, array('CMS_ACCESS_Security', 'CMS_ACCESS'))); } public function testLeftAndMainAccessAll() {