Change Sorter callable to class#902
Conversation
f01ff41 to
324ce6d
Compare
| interface Sorter | ||
| { | ||
| /** @param AvailableMigration[] $migrations */ | ||
| public function sort(array &$migrations) : void; |
There was a problem hiding this comment.
Should we maybe use __invoke here? Not sure what others think about that…
|
First of all, thanks for contributing! Especially to doctrine/migrations 3.x that still has to be released! You are awesome!
Can you explain the reasons behind your PR? What are the main advantages over a |
|
Thank you @goetas. Doctrine migrations 1.* and 2.* supports only one directory with migrations which was not enough for our use case. Few years ago we created ecosystem of internal bundles/libraries each with own migrations (and database tables) to simplify development process of our projects (many projects has similar features). The bundle migrations live together in the git repository of the bundle and is found automatically and run together with other migrations during the deployment process. So developer doesn't have to care of tables and their migrations of bundle which is developing by the other team. Thanks to great people working on Doctrine project it's now possible to drop our internal migrations solution and replace it with Doctrine migrations v3. But some features are still missing, I will create more PRs to improve the migrations so we can replace our solution. For this PR: |
|
If we go the way of expecting a sorter service performing the full sorting rather than expecting a comparison callback, I would at least provide a core implementation of the interface expecting a comparison callback, to make the migration easier. Btw, what kind of sorting algorithm do you have, so that it cannot be implemented as a comparator passed to |
|
Good point @stof, I can create it.
Recursive sorting. Maybe it can be implemented with |
|
Small performance question: |
This can be implemented without any issue with the current callback system. This is an example implementation using complex dependency graph resolution. use Doctrine\Migrations\Metadata\AvailableMigration;
use MJS\TopSort\Implementations\StringSort;
class MigrationSorter
{
private $deps = [];
private function buildDeps()
{
$sorter = new StringSort();
$sorter->add('package-a', ['package-c', 'package-b']);
$sorter->add('package-c', ['package-b']);
$this->deps = array_flip($sorter->sort());
}
public function __invoke(AvailableMigration $a, AvailableMigration $b):int
{
if (empty($this->deps)) {
$this->buildDeps();
}
$nsA = findPackage((string)$a->getVersion());
$nsB = findPackage((string)$b->getVersion());
return $this->deps[$nsA] <=> $this->deps[$nsB];
}
|
|
@goetas Yes, this is excatly what I said as the preprocessing - creating sorted list which will be used for Your example can be simplified replacing the class MigrationSorter
{
private $deps = [];
private function buildDeps(): void
{
$sorter = new StringSort();
$sorter->add('package-a', ['package-c', 'package-b']);
$sorter->add('package-c', ['package-b']);
$this->deps = array_flip($sorter->sort());
}
public function sort(array &$migrations) : void
{
if (empty($this->deps)) {
$this->buildDeps();
}
foreach ($this->deps as $key => &$value) {
$value = $migrations[$key];
}
$migrations = $this->deps;
}
}There is no need to use the |
|
The reason why I did it with uasort was also to avoid that users might inject more migrations in the array (as it is by reference) in this case). Uasort obliges to focus only on sorting. MJS\TopSort is resolving package dependencies, not sorting migrations. Those are two different processes. From what I know Sylius might need this. Do you know anyone from their team to give an opinion here? |
Implemented. Thank you @stof
@goetas You're right that's more safe. If possible injections of migrations are problem, we can close this PR. I have no good idea how to prevent this happen.
I have moved the sorting operation to
No, but we can ask. @pamil @Zales0123 @Tomanhez @AdamKasp @GSadee Do you have some use case for this PR? |
|
What about an interface as: interface Sorter
{
public function __invoke(AvailableMigration $a, AvailableMigration $b) : int;
}? |
|
#910 is my proposal. (that solves another issee that I did not notice before).
I have applied this performance optimization in #910 |
Summary
This PR replaces the custom callable for sorting migrations with the class implementing new interface
Doctrine\Migrations\Sorter.It can help to define different sorting algorithms not just using the function
uasort. I think it will be more universal for some edge cases.It can be merged to master (prepared v3) which has not been tagged yet.