Merge branch '3'

This commit is contained in:
Daniel Hensby 2016-06-13 12:42:03 +01:00
commit 9e3f76832b
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
25 changed files with 364 additions and 96 deletions

View File

@ -22,7 +22,7 @@ HTMLEditorConfig::get('cms')->setOptions(array(
. "-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align],"
. "-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],"
. "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class],"
. "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir],@[id,style,class]",
. "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir]",
'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name"
. "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],"
. "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]"

View File

@ -13,11 +13,11 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vybráno {num} stránek.\n\nSkutečně chcete obnovit?\n\nPodstránky archivovaných stránek budou obnoveny do nejvzšší úrovně, pokud tyto stránky budou také obnoveny.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Máte vybráno {num} stránek.\n\nSkutečně je chcete nezveřejnit?",
"CMSMAIN.SELECTONEPAGE": "Prosím, vyberte nejméně 1 stránku",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Přidat kampaň",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s položek",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s položka",
"Campaigns.PUBLISHCAMPAIGN": "Zveřejnit kampaň",
"Campaigns.REVERTCAMPAIGN": "Přepnout",
"LeftAndMain.CONFIRMUNSAVED": "Určitě chcete opustit navigaci z této stránky?\n\nUPOZORNĚNÍ: Vaše změny nebyly uloženy.\n\nStlačte OK pro pokračovat, nebo Cancel, zůstanete na této stránce.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "UPOZORNĚNÍ: Vaše změny nebyly uloženy.",
"LeftAndMain.PAGEWASDELETED": "Tato stránka byla smazána. Pro editaci stránky, vyberte ji vlevo.",

View File

@ -13,11 +13,11 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vi elektis {num} paĝo(j)n.\n\nĈu vi vere volas restaŭri al stadio?\n\nIdoj de enarĥivigitaj paĝoj estos restaŭritaj al la radika nivelo, escepte se tiuj paĝoj ankaŭ estos restaŭritaj.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Vi elektis {num} paĝo(j)n.\n\nĈi vi vere volas malpublikigi?",
"CMSMAIN.SELECTONEPAGE": "Bonvole elektu almenaŭ 1 paĝon.",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Aldoni kampanjon",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s elementoj",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s elemento",
"Campaigns.PUBLISHCAMPAIGN": "Publikigi kampanjon",
"Campaigns.REVERTCAMPAIGN": "Malfari",
"LeftAndMain.CONFIRMUNSAVED": "Ĉu vi vere volas navigi for de ĉi tiu paĝo?\n\nAVERTO: Viaj ŝanĝoj ne estas konservitaj.\n\nPremu je Akcepti por daŭrigi, aŭ Nuligi por resti ĉe la aktuala paĝo.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "AVERTO: Viaj ŝanĝoj ne estas konservitaj.",
"LeftAndMain.PAGEWASDELETED": "Ĉi tiu paĝo estas forigita. Por redakti paĝon, elektu ĝin maldekstre.",

View File

@ -13,11 +13,11 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"CMSMAIN.BATCH_RESTORE_PROMPT": "Sinulla on {num} sivu(a) valittuna.\n\nHaluatko varmasti palauttaa sivut?\n\nArkistoitujen sivujen alasivut palautetaan juuritasolle, jos niitä sivuja ei palauteta.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Sinulla on {num} sivu(a) valittuna.\n\nHaluatko varmasti poistaa julkaisusta?",
"CMSMAIN.SELECTONEPAGE": "Valitse vähintään yksi sivu",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Lisää kampanja",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s kohdetta",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s kohde",
"Campaigns.PUBLISHCAMPAIGN": "Julkaise kampanja",
"Campaigns.REVERTCAMPAIGN": "Palauta",
"LeftAndMain.CONFIRMUNSAVED": "Haluatko varmasti poistua tältä sivulta?\n\nVAROITUS: Muutoksiasi ei ole tallennettu.\n\nPaina OK jatkaaksesi, tai Peruuta pysyäksesi nykyisellä sivulla.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "VAROITUS: Muutoksiasi ei ole tallennettu.",
"LeftAndMain.PAGEWASDELETED": "Sivu on poistettu. Valitse sivu muokattavaksesi vasemmalta.",

View File

@ -17,7 +17,7 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.REVERTCAMPAIGN": "Whakahokia",
"LeftAndMain.CONFIRMUNSAVED": "Kei te hiahia whakatere atu i tēnei whārangi?\n\nWHAKATŪPATO: Kāore anō ō huringa kia tiakina.\n\nPēhi AE kia haere tonu, Whakakore rānei kia noho i te whārangi onāianei.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "WHAKATŪPATO: Kāore anō ō huringa kia tiakina.",
"LeftAndMain.PAGEWASDELETED": "I mukua tēnei whārangi. Hei whakatika i tētahi whārangi, tīpakohia i te taha mauī.",

View File

@ -13,11 +13,11 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vybrali ste {num} stránok.\n\nSkutočne chcete obnoviť?\n\nPodstránky archivovaných stránok budú obnovené do najvyššej úrovne, pokiaľ tieto stránky budú tiež obnovené.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Máte vybratých {num} stránok.\n\nSkutočne ich chcete nezverejniť?",
"CMSMAIN.SELECTONEPAGE": "Prosím, vyberte najmenej 1 stránku",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Pridať kampaň",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s položiek",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s položka",
"Campaigns.PUBLISHCAMPAIGN": "Zverejniť kampaň",
"Campaigns.REVERTCAMPAIGN": "Prepnúť",
"LeftAndMain.CONFIRMUNSAVED": "Určite chcete opustiť navigáciu z tejto stránky?\n\nUPOZORNENIE: Vaše zmeny neboli uložené.\n\nStlačte OK pre pokračovať, alebo Cancel, ostanete na teto stránke.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "UPOZORNENIE: Vaše zmeny neboli uložené.",
"LeftAndMain.PAGEWASDELETED": "Táto stránka bola zmazaná. Pre editáciu stránky, vyberte ju vľavo.",

View File

@ -6,11 +6,11 @@
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vybráno {num} stránek.\n\nSkutečně chcete obnovit?\n\nPodstránky archivovaných stránek budou obnoveny do nejvzšší úrovně, pokud tyto stránky budou také obnoveny.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Máte vybráno {num} stránek.\n\nSkutečně je chcete nezveřejnit?",
"CMSMAIN.SELECTONEPAGE": "Prosím, vyberte nejméně 1 stránku",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Přidat kampaň",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s položek",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s položka",
"Campaigns.PUBLISHCAMPAIGN": "Zveřejnit kampaň",
"Campaigns.REVERTCAMPAIGN": "Přepnout",
"LeftAndMain.CONFIRMUNSAVED": "Určitě chcete opustit navigaci z této stránky?\n\nUPOZORNĚNÍ: Vaše změny nebyly uloženy.\n\nStlačte OK pro pokračovat, nebo Cancel, zůstanete na této stránce.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "UPOZORNĚNÍ: Vaše změny nebyly uloženy.",
"LeftAndMain.PAGEWASDELETED": "Tato stránka byla smazána. Pro editaci stránky, vyberte ji vlevo.",

View File

@ -6,11 +6,11 @@
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vi elektis {num} paĝo(j)n.\n\nĈu vi vere volas restaŭri al stadio?\n\nIdoj de enarĥivigitaj paĝoj estos restaŭritaj al la radika nivelo, escepte se tiuj paĝoj ankaŭ estos restaŭritaj.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Vi elektis {num} paĝo(j)n.\n\nĈi vi vere volas malpublikigi?",
"CMSMAIN.SELECTONEPAGE": "Bonvole elektu almenaŭ 1 paĝon.",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Aldoni kampanjon",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s elementoj",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s elemento",
"Campaigns.PUBLISHCAMPAIGN": "Publikigi kampanjon",
"Campaigns.REVERTCAMPAIGN": "Malfari",
"LeftAndMain.CONFIRMUNSAVED": "Ĉu vi vere volas navigi for de ĉi tiu paĝo?\n\nAVERTO: Viaj ŝanĝoj ne estas konservitaj.\n\nPremu je Akcepti por daŭrigi, aŭ Nuligi por resti ĉe la aktuala paĝo.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "AVERTO: Viaj ŝanĝoj ne estas konservitaj.",
"LeftAndMain.PAGEWASDELETED": "Ĉi tiu paĝo estas forigita. Por redakti paĝon, elektu ĝin maldekstre.",

View File

@ -6,11 +6,11 @@
"CMSMAIN.BATCH_RESTORE_PROMPT": "Sinulla on {num} sivu(a) valittuna.\n\nHaluatko varmasti palauttaa sivut?\n\nArkistoitujen sivujen alasivut palautetaan juuritasolle, jos niitä sivuja ei palauteta.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Sinulla on {num} sivu(a) valittuna.\n\nHaluatko varmasti poistaa julkaisusta?",
"CMSMAIN.SELECTONEPAGE": "Valitse vähintään yksi sivu",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Lisää kampanja",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s kohdetta",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s kohde",
"Campaigns.PUBLISHCAMPAIGN": "Julkaise kampanja",
"Campaigns.REVERTCAMPAIGN": "Palauta",
"LeftAndMain.CONFIRMUNSAVED": "Haluatko varmasti poistua tältä sivulta?\n\nVAROITUS: Muutoksiasi ei ole tallennettu.\n\nPaina OK jatkaaksesi, tai Peruuta pysyäksesi nykyisellä sivulla.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "VAROITUS: Muutoksiasi ei ole tallennettu.",
"LeftAndMain.PAGEWASDELETED": "Sivu on poistettu. Valitse sivu muokattavaksesi vasemmalta.",

View File

@ -10,7 +10,7 @@
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.REVERTCAMPAIGN": "Whakahokia",
"LeftAndMain.CONFIRMUNSAVED": "Kei te hiahia whakatere atu i tēnei whārangi?\n\nWHAKATŪPATO: Kāore anō ō huringa kia tiakina.\n\nPēhi AE kia haere tonu, Whakakore rānei kia noho i te whārangi onāianei.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "WHAKATŪPATO: Kāore anō ō huringa kia tiakina.",
"LeftAndMain.PAGEWASDELETED": "I mukua tēnei whārangi. Hei whakatika i tētahi whārangi, tīpakohia i te taha mauī.",

View File

@ -6,11 +6,11 @@
"CMSMAIN.BATCH_RESTORE_PROMPT": "Vybrali ste {num} stránok.\n\nSkutočne chcete obnoviť?\n\nPodstránky archivovaných stránok budú obnovené do najvyššej úrovne, pokiaľ tieto stránky budú tiež obnovené.",
"CMSMAIN.BATCH_UNPUBLISH_PROMPT": "Máte vybratých {num} stránok.\n\nSkutočne ich chcete nezverejniť?",
"CMSMAIN.SELECTONEPAGE": "Prosím, vyberte najmenej 1 stránku",
"Campaigns.ADDCAMPAIGN": "Add campaign",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s items",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s item",
"Campaigns.PUBLISHCAMPAIGN": "Publish campaign",
"Campaigns.REVERTCAMPAIGN": "Revert",
"Campaigns.ADDCAMPAIGN": "Pridať kampaň",
"Campaigns.ITEM_SUMMARY_PLURAL": "%s položiek",
"Campaigns.ITEM_SUMMARY_SINGULAR": "%s položka",
"Campaigns.PUBLISHCAMPAIGN": "Zverejniť kampaň",
"Campaigns.REVERTCAMPAIGN": "Prepnúť",
"LeftAndMain.CONFIRMUNSAVED": "Určite chcete opustiť navigáciu z tejto stránky?\n\nUPOZORNENIE: Vaše zmeny neboli uložené.\n\nStlačte OK pre pokračovať, alebo Cancel, ostanete na teto stránke.",
"LeftAndMain.CONFIRMUNSAVEDSHORT": "UPOZORNENIE: Vaše zmeny neboli uložené.",
"LeftAndMain.PAGEWASDELETED": "Táto stránka bola zmazaná. Pre editáciu stránky, vyberte ju vľavo.",

View File

@ -162,7 +162,24 @@ trait CustomMethods {
}
}
/**
* @param object $extension
* @return array
*/
protected function findMethodsFromExtension($extension) {
if (method_exists($extension, 'allMethodNames')) {
if ($extension instanceof \Extension) $extension->setOwner($this);
$methods = $extension->allMethodNames(true);
if ($extension instanceof \Extension) $extension->clearOwner();
} else {
if (!isset(self::$built_in_methods[$extension->class])) {
self::$built_in_methods[$extension->class] = array_map('strtolower', get_class_methods($extension));
}
$methods = self::$built_in_methods[$extension->class];
}
return $methods;
}
/**
* Add all the methods from an object property (which is an {@link Extension}) to this object.
@ -175,29 +192,14 @@ trait CustomMethods {
$class = get_class($this);
$extension = ($index !== null) ? $this->{$property}[$index] : $this->$property;
if(!$extension) {
throw new InvalidArgumentException (
if (!$extension) {
throw new InvalidArgumentException(
"Object->addMethodsFrom(): could not add methods from {$class}->{$property}[$index]"
);
}
if(method_exists($extension, 'allMethodNames')) {
if ($extension instanceof \Extension) {
$extension->setOwner($this);
}
$methods = $extension->allMethodNames(true);
if ($extension instanceof \Extension) {
$extension->clearOwner();
}
} else {
if(!isset(self::$built_in_methods[$extension->class])) {
self::$built_in_methods[$extension->class] = array_map('strtolower', get_class_methods($extension));
}
$methods = self::$built_in_methods[$extension->class];
}
if($methods) {
$methods = $this->findMethodsFromExtension($extension);
if ($methods) {
$methodInfo = array(
'property' => $property,
'index' => $index,
@ -215,6 +217,37 @@ trait CustomMethods {
}
}
/**
* Add all the methods from an object property (which is an {@link Extension}) to this object.
*
* @param string $property the property name
* @param string|int $index an index to use if the property is an array
*/
protected function removeMethodsFrom($property, $index = null) {
$extension = ($index !== null) ? $this->{$property}[$index] : $this->$property;
if (!$extension) {
throw new InvalidArgumentException(
"Object->removeMethodsFrom(): could not remove methods from {$this->class}->{$property}[$index]"
);
}
$methods = $this->findMethodsFromExtension($extension);
if ($methods) {
foreach ($methods as $method) {
$methodInfo = self::$extra_methods[$this->class][$method];
if ($methodInfo['property'] === $property && $methodInfo['index'] === $index) {
unset(self::$extra_methods[$this->class][$method]);
}
}
if (empty(self::$extra_methods[$this->class])) {
unset(self::$extra_methods[$this->class]);
}
}
}
/**
* Add a wrapper method - a method which points to another method with a different name. For example, Thumbnail(x)
* can be wrapped to generateThumbnail(x)

View File

@ -13,32 +13,40 @@ class TokenisedRegularExpression {
*/
protected $expression;
/**
* The first expression to match
*/
protected $firstMatch;
public function __construct($expression) {
$this->expression = $expression;
$this->firstMatch = is_array($expression[0]) ? $expression[0][0] : $expression[0];
}
public function findAll($tokens) {
$tokenTypes = array();
foreach($tokens as $i => $token) {
if(is_array($token)) {
$tokenTypes[$i] = $token[0];
$tokenType = $token[0];
} else {
$tokenTypes[$i] = $token;
$tokenType = $token;
// Pre-process string tokens for matchFrom()
$tokens[$i] = array($token, $token);
}
if ($tokenType == $this->firstMatch) {
$tokenTypes[$i] = $tokenType;
}
}
$startKeys = array_keys($tokenTypes, is_array($this->expression[0])
? $this->expression[0][0] : $this->expression[0]);
$allMatches = array();
foreach($startKeys as $startKey) {
foreach($tokenTypes as $startKey => $dud) {
$matches = array();
if($this->matchFrom($startKey, 0, $tokens, $matches)) {
$allMatches[] = $matches;
}
}
return $allMatches;
}

View File

@ -343,7 +343,11 @@ class BulkLoader_Result extends Object {
* @return ArrayList
*/
public function Deleted() {
return $this->mapToArrayList($this->deleted);
$set = new ArrayList();
foreach ($this->deleted as $arrItem) {
$set->push(ArrayData::create($arrItem));
}
return $set;
}
/**
@ -386,11 +390,9 @@ class BulkLoader_Result extends Object {
* @param $message string
*/
public function addDeleted($obj, $message = null) {
$this->deleted[] = $this->lastChange = array(
'ID' => $obj->ID,
'ClassName' => $obj->class,
'Message' => $message
);
$data = $obj->toMap();
$data['_BulkLoaderMessage'] = $message;
$this->deleted[] = $this->lastChange = $data;
$this->lastChange['ChangeType'] = 'deleted';
}

View File

@ -46,7 +46,7 @@ and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDa
'MyDate' => 'Date'
);
public function getCustomSearchContext() {
public function getDefaultSearchContext() {
$fields = $this->scaffoldSearchFields(array(
'restrictFields' => array('PublicProperty','MyDate')
));

View File

@ -1,4 +1,4 @@
# 3.4.0 (unreleased)
# 3.4.0
## Upgrading notes
@ -31,3 +31,57 @@ code can be turned on by setting `Debug.friendly_error_httpcode` config to true.
Debug:
friendly_error_httpcode: true
<!--- Changes below this line will be automatically regenerated -->
## Change Log
### API Changes
* 2016-05-18 [c55777c](https://github.com/silverstripe/silverstripe-installer/commit/c55777c9af3c257c755b9a82871866410968df82) Enable friendly error HTTP code by default for new projects (Damian Mooyman)
* 2016-05-18 [757cfae](https://github.com/silverstripe/silverstripe-framework/commit/757cfae90cdef590202f0cbcdf67e180df484a1b) Enable Debug.friendly_error_httpcode to correctly set HTTP status code for errors (Damian Mooyman)
* 2016-05-12 [7041c59](https://github.com/silverstripe/silverstripe-framework/commit/7041c5945c247c1e104507bfe5751d24543aa38c) Enable requirements to persist between flushes (Damian Mooyman)
* 2016-04-19 [43b0052](https://github.com/silverstripe/silverstripe-framework/commit/43b00520feba68e71b8ec70336cd7923113ffcb0) Remove artifact datalist overrides from UnsavedRelationList (Damian Mooyman)
* 2016-03-07 [634e86f](https://github.com/silverstripe/silverstripe-framework/commit/634e86f949e0ced1eb5e14c9bb7ec43ecc52652c) Include File.ParentID in fulltext search results (Damian Mooyman)
* 2015-12-13 [62f183d](https://github.com/silverstripe/silverstripe-framework/commit/62f183d03792c1bd1e0e2e385ca587b94de08d83) before/afterExtend now support parameters passed by reference (Damian Mooyman)
* 2015-11-25 [3842971](https://github.com/silverstripe/silverstripe-framework/commit/384297150a97c84bac05870b77ea7a736b20f553) refactor LeftAndMain_Menu.ss into individually overridable components (Damian Mooyman)
* 2015-08-28 [f6fe142](https://github.com/silverstripe/silverstripe-framework/commit/f6fe1427c286fa5fc58b83cd10d84bf5930889e2) Making ArrayList (and others) more consistent with DataList (Daniel Hensby)
### Features and Enhancements
* 2016-03-27 [1e7281a](https://github.com/silverstripe/silverstripe-framework/commit/1e7281a2ba70b6281e6e72070e2fdb559b406c98) Add onBeforeRender() hook to GridField (Loz Calver)
* 2016-03-15 [2923787](https://github.com/silverstripe/silverstripe-framework/commit/292378735251afe221f77c097095c859dc49caf5) consistent file icons (Jonathon Menz)
* 2016-02-23 [375bbf9](https://github.com/silverstripe/silverstripe-framework/commit/375bbf954e0b1d24e6119edec267608a8d0ec85c) and fix for issue #3186 (Tyler Kidd)
* 2016-02-22 [01c8d38](https://github.com/silverstripe/silverstripe-framework/commit/01c8d388854466642b6fcc624d6b35b39e44bf7a) Passing $tmpFile to extension. (Taras Yemtsov)
* 2015-12-22 [c9ba0e4](https://github.com/silverstripe/silverstripe-framework/commit/c9ba0e48fc927557b34faec5c672a80709ad0632) Add ViewableData::setFailover() to refresh detected methods when changing failover (Loz Calver)
### Bugfixes
* 2016-05-18 [62bd26d](https://github.com/silverstripe/silverstripe-framework/commit/62bd26d11ab9c9bf5b91ba8abb776ab3a4813a18) Fix suppression of display_errors in ErrorControlChain (Damian Mooyman)
* 2016-05-17 [8ed25ae](https://github.com/silverstripe/silverstripe-framework/commit/8ed25ae4829c03e51bf63c35b2bbff8fa078d324) Fix DataObject::isChanged() detecting non saveable changes (#5545) (Damian Mooyman)
* 2016-05-17 [8947bb0](https://github.com/silverstripe/silverstripe-framework/commit/8947bb0245c2be23f9ec3ad1d2dcd6b554182f4f) Fix filtersOnId ignoring `WHERE "ID" IN ()` (#5546) (Damian Mooyman)
* 2016-05-17 [829f59e](https://github.com/silverstripe/silverstripe-framework/commit/829f59e4437b0a99ab06889784f713d1f9a456f0) Fix link dialog box layout in CMS (Damian Mooyman)
* 2016-05-16 [79d0590](https://github.com/silverstripe/silverstripe-framework/commit/79d05906286698e7cf7274703088a47c54b106f2) Fix singleton('DBLocale') (Damian Mooyman)
* 2016-05-13 [4d1ddf0](https://github.com/silverstripe/silverstripe-framework/commit/4d1ddf0e62c7565a9650ebcef9dd51bbd6d9a83c) Prevent session hijackers from resetting a user password (Damian Mooyman)
* 2016-05-10 [3738d88](https://github.com/silverstripe/silverstripe-framework/commit/3738d888e0fbce48e0d88735edd3455a116937b5) Empty FROM clause (Daniel Hensby)
* 2016-05-10 [d1df67d](https://github.com/silverstripe/silverstripe-framework/commit/d1df67d3089a51c0db63fbaed869738453bee482) SQLSelect count methods now cast to int (fixes #5498) (Loz Calver)
* 2016-05-05 [cc7a2ae](https://github.com/silverstripe/silverstripe-installer/commit/cc7a2aeb1e03f3f8db67a1ca547280b05dd9372a) Add framework/admin tests (#118) (Daniel Hensby)
* 2016-05-02 [096f30e](https://github.com/silverstripe/silverstripe-framework/commit/096f30ebe5ff6446a399abc92813a6ff2d02e04e) Fix GridFieldAddExistingAutocompleter (Damian Mooyman)
* 2016-04-28 [6934083](https://github.com/silverstripe/silverstripe-framework/commit/693408330bdd235b92690912ad36ba8adbebdbef) for #5410 to help focus errors occurring on tabs within GridField controlled DataObjects (et al). (Patrick Nelson)
* 2016-04-21 [fa5b8b8](https://github.com/silverstripe/silverstripe-framework/commit/fa5b8b8fb13661490fd518777305c5e3dd22309b) Fix error when modals are displayed (Damian Mooyman)
* 2016-04-21 [b4f466f](https://github.com/silverstripe/silverstripe-cms/commit/b4f466f5e10cde3d691280258cd4920c58f0ab65) Correct framework/module dependencies for cms (Damian Mooyman)
* 2016-04-21 [ae268ae](https://github.com/silverstripe/silverstripe-framework/commit/ae268ae4df11a59d9bdf941f1ae9789461fa7d75) #5363 Add .JSON option for templates (Robbie Averill)
* 2016-03-29 [7907d20](https://github.com/silverstripe/silverstripe-framework/commit/7907d20da7af4c2945fa2ced2963eb938bee4f3c) changing all cases of filesize spelling to file size (Tim Kung)
* 2016-03-17 [96c586b](https://github.com/silverstripe/silverstripe-framework/commit/96c586b39d8c06d439e67a2a6df33ada97fe8dd1) only output $CleartextPassword if it has a value (Christopher Darling)
* 2016-02-12 [a34f17f](https://github.com/silverstripe/silverstripe-framework/commit/a34f17f83970f4bfb04e6c80188ca36a29125dd2) for #5028: Ensure empty YML configs don't break when merging them in (i.e. make sure it's traversable before foreach'ing over it). (Patrick Nelson)
* 2016-01-26 [b1b403c](https://github.com/silverstripe/silverstripe-cms/commit/b1b403cd089ee2fcb6ed28d62fa3e81f00a18f4d) Borders on CMS Actions (Daniel Hensby)
* 2016-01-26 [c5fc9dd](https://github.com/silverstripe/silverstripe-framework/commit/c5fc9dd65003788c8dcf9ebf64065be9ec468b1d) CMS actions alignment (Daniel Hensby)
* 2016-01-12 [a7110be](https://github.com/silverstripe/silverstripe-framework/commit/a7110bef703db749ebfea6da1e9d10c310e0624a) OptionsetField uses aria-required (Torleif West)
* 2016-01-11 [122784b](https://github.com/silverstripe/silverstripe-framework/commit/122784b1cb93c5892f1f02cd50cc79297177ea19) OptionsetField input has required #4901 (torleif)
* 2016-01-11 [288c8a8](https://github.com/silverstripe/silverstripe-framework/commit/288c8a8b272af85cf1b62d82b5633e16bbf44d15) OptionsetField returns valid HTML #4901 (torleif)
* 2016-01-06 [bf6337c](https://github.com/silverstripe/silverstripe-cms/commit/bf6337c59a291124985a4ea6b490c304193d7b25) Changes needed to respond to whitespace changes. (Sam Minnee)
* 2016-01-06 [4aa5053](https://github.com/silverstripe/silverstripe-framework/commit/4aa50534d566722df81bfac8efd2c3db7ed92596) Fixes needed to adapt to whitespace changes. (Sam Minnee)
* 2015-12-22 [24660af](https://github.com/silverstripe/silverstripe-framework/commit/24660afabd7ddcaf87aa859df396862cecea2ef8) Parameters passed to includes overwrite all scopes (fixes #2617) (Loz Calver)
* 2015-11-04 [fb43e59](https://github.com/silverstripe/silverstripe-cms/commit/fb43e59b0024ee5dea3b64447d1075ec151ac11c) Setting hide_ancestor=true causes a random page type to be hidden (Loz Calver)
* 2015-10-07 [7a81372](https://github.com/silverstripe/silverstripe-framework/commit/7a813722946d3c25afecba682c3ad41c01c3992c) castingHelper failed to find many_many_extraFields data (fixes #4661) (Loz Calver)
* 2015-08-04 [e94c0fa](https://github.com/silverstripe/silverstripe-framework/commit/e94c0fa221a65fdac1a6604b839901e438592093) extraClass() method to match parent method (Florian Thoma)
* 2014-10-29 [61a9b2a](https://github.com/silverstripe/silverstripe-framework/commit/61a9b2a41a7ad6f4b47f65d4badb9e583469fda1) GridFieldPaginator now prevents viewing pages with no results (fixes #3192) (Loz Calver)

View File

@ -170,7 +170,9 @@ class DataQuery {
* @return SQLSelect The finalised sql query
*/
public function getFinalisedQuery($queriedColumns = null) {
if(!$queriedColumns) $queriedColumns = $this->queriedColumns;
if(!$queriedColumns) {
$queriedColumns = $this->queriedColumns;
}
if($queriedColumns) {
$queriedColumns = array_merge($queriedColumns, array('Created', 'LastEdited', 'ClassName'));
}
@ -185,11 +187,19 @@ class DataQuery {
// Specifying certain columns allows joining of child tables
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
// Ensure that any filtered columns are included in the selected columns
foreach ($query->getWhereParameterised($parameters) as $where) {
// Check for just the column, in the form '"Column" = ?' and the form '"Table"."Column"' = ?
if (preg_match('/^"([^"]+)"/', $where, $matches) ||
preg_match('/^"([^"]+)"\."[^"]+"/', $where, $matches)) {
if (!in_array($matches[1], $queriedColumns)) $queriedColumns[] = $matches[1];
// Check for any columns in the form '"Column" = ?' or '"Table"."Column"' = ?
if(preg_match_all(
'/(?:"(?<table>[^"]+)"\.)?"(?<column>[^"]+)"(?:[^\.]|$)/',
$where, $matches, PREG_SET_ORDER
)) {
foreach($matches as $match) {
$column = $match['column'];
if (!in_array($column, $queriedColumns)) {
$queriedColumns[] = $column;
}
}
}
}
} else {

View File

@ -67,21 +67,21 @@ class MemberLoginForm extends LoginForm {
}
if($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) {
$fields = new FieldList(
new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this)
$fields = FieldList::create(
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this)
);
$actions = new FieldList(
new FormAction("logout", _t('Member.BUTTONLOGINOTHER', "Log in as someone else"))
$actions = FieldList::create(
FormAction::create("logout", _t('Member.BUTTONLOGINOTHER', "Log in as someone else"))
);
} else {
if(!$fields) {
$label=singleton('Member')->fieldLabel(Member::config()->unique_identifier_field);
$fields = new FieldList(
new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
$fields = FieldList::create(
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this),
// Regardless of what the unique identifer field is (usually 'Email'), it will be held in the
// 'Email' value, below:
$emailField = new TextField("Email", $label, null, null, $this),
new PasswordField("Password", _t('Member.PASSWORD', 'Password'))
$emailField = TextField::create("Email", $label, null, null, $this),
PasswordField::create("Password", _t('Member.PASSWORD', 'Password'))
);
if(Security::config()->remember_username) {
$emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email'));
@ -106,9 +106,9 @@ class MemberLoginForm extends LoginForm {
}
}
if(!$actions) {
$actions = new FieldList(
new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")),
new LiteralField(
$actions = FieldList::create(
FormAction::create('dologin', _t('Member.BUTTONLOGIN', "Log in")),
LiteralField::create(
'forgotPassword',
'<p id="ForgotPassword"><a href="Security/lostpassword">'
. _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'
@ -118,7 +118,7 @@ class MemberLoginForm extends LoginForm {
}
if(isset($backURL)) {
$fields->push(new HiddenField('BackURL', 'BackURL', $backURL));
$fields->push(HiddenField::create('BackURL', 'BackURL', $backURL));
}
// Reduce attack surface by enforcing POST requests
@ -126,7 +126,7 @@ class MemberLoginForm extends LoginForm {
parent::__construct($controller, $name, $fields, $actions);
$this->setValidator(new RequiredFields('Email', 'Password'));
$this->setValidator(RequiredFields::create('Email', 'Password'));
// Focus on the email input when the page is loaded
$js = <<<JS
@ -212,7 +212,7 @@ JS;
if(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) {
Session::set('BackURL', $backURL);
}
$cp = new ChangePasswordForm($this->controller, 'ChangePasswordForm');
$cp = ChangePasswordForm::create($this->controller, 'ChangePasswordForm');
$cp->sessionMessage(
_t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'),
'good'

View File

@ -0,0 +1,94 @@
<?php
/**
* @package framework
* @subpackage tests
*/
class BulkLoaderResultTest extends SapphireTest
{
protected $extraDataObjects = array('BulkLoaderTestPlayer');
public function setUp()
{
parent::setUp();
BulkLoaderTestPlayer::create(array('Name' => 'Vincent', 'Status' => 'Available'))->write();
}
public function testBulkLoaderResultCreated()
{
$results = BulkLoader_Result::create();
$player = BulkLoaderTestPlayer::create(array('Name' => 'Rangi', 'Status' => 'Possible'));
$player->write();
$results->addCreated($player, 'Speedster');
$this->assertEquals($results->CreatedCount(), 1);
$this->assertSame(
'Rangi',
$results->Created()->find('Name', 'Rangi')->Name,
'The player Rangi should be recorded as created in $results'
);
$this->assertSame(
'Possible',
$results->Created()->find('Name', 'Rangi')->Status,
'The player Rangi should have Status of "Possible" in $results'
);
$this->assertSame(
'Speedster',
$results->Created()->find('Name', 'Rangi')->_BulkLoaderMessage,
'Rangi should have _BulkLoaderMessage of Speedster'
);
}
public function testBulkLoaderResultDeleted()
{
$results = BulkLoader_Result::create();
$player = BulkLoaderTestPlayer::get()->find('Name', 'Vincent');
$results->addDeleted($player, 'Retired');
$player->delete();
$this->assertEquals($results->DeletedCount(), 1);
$this->assertSame(
'Vincent',
$results->Deleted()->find('Name', 'Vincent')->Name,
'The player Vincent should be recorded as deleted'
);
$this->assertSame(
'Retired',
$results->Deleted()->find('Name', 'Vincent')->_BulkLoaderMessage,
'Vincent should have a _BulkLoaderMessage of Retired'
);
}
public function testBulkLoaderResultUpdated()
{
$results = BulkLoader_Result::create();
$player = BulkLoaderTestPlayer::get()->find('Name', 'Vincent');
$player->Status = 'Unavailable';
$player->write();
$results->addUpdated($player, 'Injured');
$this->assertEquals($results->UpdatedCount(), 1);
$this->assertSame(
'Vincent',
$results->Updated()->find('Name', 'Vincent')->Name,
'The player Vincent should be recorded as updated'
);
$this->assertSame(
'Unavailable',
$results->Updated()->find('Name', 'Vincent')->Status,
'The player Vincent should have a Status of Unavailable'
);
$this->assertSame(
'Injured',
$results->Updated()->find('Name', 'Vincent')->_BulkLoaderMessage,
'Vincent is injured'
);
}
}
class BulkLoaderTestPlayer extends DataObject implements TestOnly
{
private static $db = array(
'Name' => 'Varchar',
'Status' => 'Varchar',
);
}

View File

@ -277,6 +277,45 @@ class DataQueryTest extends SapphireTest {
$this->resetDBSchema(true);
}
/**
* Tests that getFinalisedQuery can include all tables
*/
public function testConditionsIncludeTables() {
// Including filter on parent table only doesn't pull in second
$query = new DataQuery('DataQueryTest_C');
$query->sort('"SortOrder"');
$query->where(array(
'"DataQueryTest_C"."Title" = ?' => array('First')
));
$result = $query->getFinalisedQuery(array('Title'));
$from = $result->getFrom();
$this->assertContains('DataQueryTest_C', array_keys($from));
$this->assertNotContains('DataQueryTest_E', array_keys($from));
// Including filter on sub-table requires it
$query = new DataQuery('DataQueryTest_C');
$query->sort('"SortOrder"');
$query->where(array(
'"DataQueryTest_C"."Title" = ? OR "DataQueryTest_E"."SortOrder" > ?' => array(
'First', 2
)
));
$result = $query->getFinalisedQuery(array('Title'));
$from = $result->getFrom();
// Check that including "SortOrder" prompted inclusion of DataQueryTest_E table
$this->assertContains('DataQueryTest_C', array_keys($from));
$this->assertContains('DataQueryTest_E', array_keys($from));
$arrayResult = iterator_to_array($result->execute());
$first = array_shift($arrayResult);
$this->assertNotNull($first);
$this->assertEquals('First', $first['Title']);
$second = array_shift($arrayResult);
$this->assertNotNull($second);
$this->assertEquals('Last', $second['Title']);
$this->assertEmpty(array_shift($arrayResult));
}
}

View File

@ -0,0 +1 @@
$Title<% with $Item %> - <% with $Up %>$Title<% end_with %> - <% with $NestedItem %><% with $Top %>$Title<% end_with %><% end_with %><% end_with %>

View File

@ -716,6 +716,16 @@ after')
'A - B - C - B - A'
);
$this->assertEquals(
$this->render('<% include SSViewerTestIncludeScopeInheritanceWithUpAndTop Title="A" %>',
new ArrayData(array(
'Item' => new ArrayData(array(
'Title' =>'B', 'NestedItem' => new ArrayData(array('Title' => 'C'))
)))
)),
'A - A - A'
);
$data = new ArrayData(array(
'Nested' => new ArrayData(array(
'Object' => new ArrayData(array('Key' => 'A'))

View File

@ -187,6 +187,11 @@ class ViewableDataTest extends SapphireTest {
// Ensure that defined methods detected from the failover aren't cached when setting a new failover
$container->setFailover(new ViewableDataTest_Failover);
$this->assertTrue($container->hasMethod('testMethod'));
// Test the reverse - that defined methods previously detected in a failover are removed if they no longer exist
$container->setFailover($failover);
$this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object');
$this->assertFalse($container->hasMethod('testMethod'), 'testMethod() incorrectly reported as existing');
}
}

View File

@ -560,12 +560,15 @@ class SSViewer_DataPresenter extends SSViewer_Scope {
*/
public function pushScope() {
$scope = parent::pushScope();
$upIndex = $this->getUpIndex();
if ($upIndex !== null) {
$itemStack = $this->getItemStack();
$itemStack[$this->getUpIndex()][SSViewer_Scope::ITEM_OVERLAY] = $this->overlay;
$itemStack[$upIndex][SSViewer_Scope::ITEM_OVERLAY] = $this->overlay;
$this->setItemStack($itemStack);
$this->overlay = array();
}
return $scope;
}
@ -577,8 +580,12 @@ class SSViewer_DataPresenter extends SSViewer_Scope {
* @return SSViewer_Scope
*/
public function popScope() {
$upIndex = $this->getUpIndex();
if ($upIndex !== null) {
$itemStack = $this->getItemStack();
$this->overlay = $itemStack[$this->getUpIndex()][SSViewer_Scope::ITEM_OVERLAY];
}
return parent::popScope();
}

View File

@ -137,6 +137,11 @@ class ViewableData extends Object implements IteratorAggregate {
* @param ViewableData $failover
*/
public function setFailover(ViewableData $failover) {
// Ensure cached methods from previous failover are removed
if ($this->failover) {
$this->removeMethodsFrom('failover');
}
$this->failover = $failover;
$this->defineMethods();
}