This would ideally be fixed with the ability to use an external library
like gettext, but that's an API change. This for now fixes the issue
where a singular like "Page" returns "Pags" for the plural name.
Database abstraction broken up into controller, connector, query builder, and schema manager, each independently configurable via YAML / Injector
Creation of new DBQueryGenerator for database specific generation of SQL
Support for parameterised queries, move of code base to use these over escaped conditions
Refactor of SQLQuery into separate query classes for each of INSERT UPDATE DELETE and SELECT
Support for PDO
Installation process upgraded to use new ORM
SS_DatabaseException created to handle database errors, maintaining details of raw sql and parameter details for user code designed interested in that data.
Renamed DB static methods to conform correctly to naming conventions (e.g. DB::getConn -> DB::get_conn)
3.2 upgrade docs
Performance Optimisation and simplification of code to use more concise API
API Ability for database adapters to register extensions to ConfigureFromEnv.php
DataObject::validate() is currently set to protected, but this means
you can't call validate() from outside the context of itself unless
you overload the method to use a public visibility and then call
parent::validate()
As it would turn out, most classes that overload this method already
set the visibility to public, so it would make sense the parent matches
that as well.
If we want DataObject->validate() to be used instead of
the form layer, we should allow for validation errors
to be passed through unchanged to the controller layer
so we can present them to the user. The context of
which class is written should be apparent from the stacktrace
of the exception.
Commit 964b3f2 fixed an issue where dbObject was returning casting helpers for
fields that were not actually DB objects, but had something in $casting config.
However, because dbObject was no longer calling DataObject->castingHelper, this
exposed a bug that the underlying function db($fieldName) was not returning
field specs for the base fields that are created by SS automatically on all
DataObjects (i.e. Created, LastEdited, etc).
This commit fixes the underlying issue that DataObject->db($fieldName) should
return the field specs for *all* DB fields like its documentation says it will,
including those base fields that are automatically created and do not appear in
$db.
Since ViewableData was returning a casting helper for Link, but DataObject was
only using $this->$fieldname to set values on that casting helper, you could
not use <% if Link %> (or <% if $Link %>) in your templates because Link is not
a field, and thus had no value to be set on the casting helper, causing
hasValue to think that there was no value. Since DataObject->dbObject says that
"it only matches fields and not methods", it seems safe to have it call db(..)
to get the field spec, and not call ViewableData->castingHelper at all.
This caused problems when duplicate() was used in the CMS UI
to duplicate a SiteTree object. Since every object of this type
has a ParentID relation, it copied this empty relation into
new "ghost page".
See https://github.com/silverstripe/silverstripe-cms/issues/689
When DataObject::update() is run with relation fields and the relationship
is new the relationship ID was not set on the DataObject. This patch fixes
this. Fixes issue 6195 in open.silverstripe.org.
$forceWrite was being ignored because it was tested in a part of the
code that is reachable if and only if there are changes to the object.
This patch adds an additional test to correct that logic error.
Also, refrain from needlessly checking for changes when $forceWrite is
true.
Fixes#1687
API: CompositeDBField::setValue() may be passed an object as its second argument, in addition to array.
These changes provide a 15% - 20% performance improvement, and as such justify an small API change in the 3.0 branch. It will likely affect anyone who has created their own composite fields, which is fortunately not all that common.
Lazy loading no longer loads fields from the versions table when querying. This could lead to incorrect data being displayed if the data on the object and the version it pointed to did not match.
API methods to allow setting of the context of the query that generated the DataObject on that object (used by the lazy loading mechanism to correctly query the Stage, Live, or Versions tables)
See https://github.com/silverstripe/sapphire/pull/1178 for context.
Lazy loading no longer loads fields from the versions table when querying. This could lead to incorrect data being displayed if the data on the object and the version it pointed to did not match.
API methods to allow setting of the context of the query that generated the DataObject on that object (used by the lazy loading mechanism to correctly query the Stage, Live, or Versions tables)
See https://github.com/silverstripe/sapphire/pull/1178 for context.
Before this was only possible for some specific ones, like onBeforeWrite.
This excludes any callbacks with augment*() or update*() naming,
since these are assumed to be on extension only, with a corresponding
base method available on the class itself (e.g. "updateCMSFields()"
vs "getCMSFields()").
This causes a 'Fatal error: Call to a member function hasMethod() on a non-object'.
This can happen when displaying a field in a gridfield on a belongs_to relationship.
In 3.0 there was some confusion about whether DataLists and ArrayLists
were mutable or not. If DataLists were immutable, they'd return the result, and your code
would look like
$list = $list->filter(....);
If DataLists were mutable, they'd operate on themselves, returning nothing, and your code
would look like
$list->filter(....);
This makes all DataLists and ArrayList immutable for all _searching_ operations.
Operations on DataList that modify the underlying SQL data store remain mutating.
- These functions no longer mutate the existing object, and if you do not capture the value
returned by them will have no effect:
ArrayList#reverse
ArrayList#sort
ArrayList#filter
ArrayList#exclude
DataList#dataQuery (use DataList#alterDataQuery to modify dataQuery in a safe manner)
DataList#where
DataList#limit
DataList#sort
DataList#addFilter
DataList#applyFilterContext
DataList#innerJoin
DataList#leftJoin
DataList#find
DataList#byIDs
DataList#reverse
- DataList#setDataQueryParam has been added as syntactic sugar around the most common
cause of accessing the dataQuery directly - setting query parameters
- RelationList#setForeignID has been removed. Always use RelationList#forForeignID
when querying, and overload RelationList#foreignIDList when subclassing.
- Relatedly,the protected variable RelationList->foreignID has been removed, as the ID is
now stored on a query parameter. Use RelationList#getForeignID to read it.
Avoid PHPUnit throwing "test didn't run any assertions"
notices in PHP. If nothing else, it keeps test output
looking less broken by default, making it more likely
that actual errors do get noticed.
In a usual CMS request, DataObject::db() is called potentially
thousands of times, calling Config::get() constantly for the same
uninherited statics, which is slow. This improves performance
by caching those into DataObject::$_cache_db
On sites with lots of modules, and pages with plenty of database
queries, DataObject::custom_database_fields() can be called
thousands of times, and slow down page render times. This fixes
it so the fields are cached by class in a static variable, and
are cleared when reset() is called on the DataObject.
In cases where a getter on a DataObject calls getComponent() or
other relational getter, $this->model won't have been set at
this point, and a fatal error is triggered.
This fixes it so $this->model is set *before* populateDefaults()
in DataObject::__construct() and the getters can operate normally.