CRM-20345 - CRM_Utils_SQL_Select::orderBy() (#4)
authorTim Otten <totten@civicrm.org>
Sat, 1 Apr 2017 01:59:44 +0000 (18:59 -0700)
committercolemanw <coleman@civicrm.org>
Sat, 1 Apr 2017 01:59:44 +0000 (21:59 -0400)
commit6db70618decf91e004452cf1a8f36c6536a71e8c
treedc671f4aea79cf7c86f9e9801b4569accc5e6d68
parent7a51786de3aac980749dc40f6fea54cffdc5958e
CRM-20345 - CRM_Utils_SQL_Select::orderBy() (#4)

* CRM-20345 - CRM_Utils_Array::crmArraySortByField - Add test. Allow multiple fields.

* CRM-20345 - CRM_Utils_SQL_Select::orderBy - Use more deterministic ordering

The technique of computing default `$weight = count($this->orderBys)`
addresses a valid point: we need to preserve ordering for existing callers
who don't specify weights -- while also allowing weights.

However, it feels weird in my gut. Not sure why -- maybe it's something like this:

```php
// A1: Non-deterministic ordering
$select->orderBy('alpha', 1);
$select->orderBy('beta');
$select->orderBy('delta', 2);
$select->orderBy('gamma', 3);

// A2: Deterministic ordering
$select->orderBy('alpha', 10);
$select->orderBy('beta');
$select->orderBy('delta', 20);
$select->orderBy('gamma', 30);

// B1: Deterministic ordering
$select->orderBy('alpha');
$select->orderBy('beta');
$select->orderBy('delta');
$select->orderBy('gamma');

// B2: Non-deterministic ordering
$select->orderBy('alpha', 1);
$select->orderBy('beta', 1);
$select->orderBy('delta', 1);
$select->orderBy('gamma', 1);
```

As a reader, I would expect A1/A2 to be the same, and I would expect B1/B2
to be the same.  But they're not.  If there's a collision in the `weight`s,
the ordering becomes non-deterministic (depending on obscure details or
happenstance of the PHP runtime).

Of course, there's no right answer: in A1/A2, you can plausibly put `beta`
before `alpha` or after `alpha` or after `gamma`.  But it should be
determinstic so that it always winds up in the same place.
CRM/Utils/Array.php
CRM/Utils/SQL/Select.php
tests/phpunit/CRM/Utils/ArrayTest.php