Most of the changes will be simple pattern replacements, to do that we need to take into account some base behavior/abilities.
Before we read and change code, we need to format it to ensure no missed patterns due to unexpected formatting.
For every file we visit (JS or PHP) before we get to the petterns, we need to parse the imports and have solid logic (using lexers) to add/remove imports. Then we can read the pattern replacements and apply any import changes that come with based on what the replacement needs.
Detective steps (:p) where we look into code, gather information, delete code, regenerate new code based on gathered info in hopes that no info was lost (tricky, might drop this idea).
Dependencies β
composer.json.require.flarum/* ^2.0 (when not set to*)
composer.json.require-dev.flarum/* ^2.0 (when not set to*)
Infra β
flarum/framework/.github/workflows/REUSABLE_backend.yml@main or @1.x => @2.x
flarum/framework/.github/workflows/REUSABLE_frontend.yml@main or @1.x => @2.x
phpstan
Frontend
mithril 2.0 -> 2.2
can't find exact instances of this in the code, but the more common instance is a copy from core of:
before
return [
<li className="Dropdown-header">{app.translator.trans('core.forum.search.users_heading')}</li>,
...results.map((user) => {
const name = username(user);
const children = [highlight(name.text as string, query)];
return (
<li className="UserSearchResult" data-index={'users' + user.id()}>
<Link href={app.route.user(user)}>
{avatar(user)}
{{ ...name, text: undefined, children }}
</Link>
</li> );
}),
];
// before
League\Flysystem\Adapter\NullAdapter
NullAdapter
// after
League\Flysystem\InMemory\InMemoryFilesystemAdapter
InMemoryFilesystemAdapter
// Before
League\Flysystem\Adpter\Local
Local
// after
League\Flysystem\Local\LocalFilesystemAdapter
LocalFilesystemAdapter
β
// before
new FilesystemAdapter(new Filesystem(new LocalAdapter($path)));
// after
new FilesystemAdapter(new Filesystem($adapter = new LocalAdapter($path)), $adapter);
add before and after changes as an example (use the tags extension) β
create an api resource class for each type of serialized model β
Pre-fill the API resource with endpoints based on the current controllers β
Pre-fill the API resource with relationship declarations based on the Serializer β
auto insert the extender that registers the new api resource class β
add TODO comments on old classes (Serializers and Controllers) and old extenders, so the author knows to migrate their logic to the new api resource class. β
Search
Gambits (back to front) (produced js gambit based on pattern) β
// before
class TagFilterGambit extends AbstractRegexGambit implements FilterInterface
{
use ValidateFilterTrait;
/**
* @var SlugManager
*/
protected $slugger;
public function __construct(SlugManager $slugger)
{
$this->slugger = $slugger;
}
protected function getGambitPattern()
{
return 'tag:(.+)';
}
protected function conditions(SearchState $search, array $matches, $negate)
{
...
}
public function getFilterKey(): string
{
return 'tag';
}
public function filter(FilterState $filterState, $filterValue, bool $negate)
{
$this->constrain($filterState->getQuery(), $filterValue, $negate, $filterState->getActor());
}
protected function constrain(Builder $query, $rawSlugs, $negate, User $actor)
{
...
}
}
// after
class TagFilter implements FilterInterface
{
use ValidateFilterTrait;
/**
* @var SlugManager
*/
protected $slugger;
public function __construct(SlugManager $slugger)
{
$this->slugger = $slugger;
}
public function getFilterKey(): string
{
return 'tag';
}
public function filter(FilterState $filterState, $filterValue, bool $negate)
{
$this->constrain($filterState->getQuery(), $filterValue, $negate, $filterState->getActor());
}
protected function constrain(Builder $query, $rawSlugs, $negate, User $actor)
{
...
}
// before
(new Extend\Filter(PostFilterer::class))
->addFilter(PostTagFilter::class),
(new Extend\Filter(DiscussionFilterer::class))
->addFilter(TagFilterGambit::class)
->addFilterMutator(HideHiddenTagsFromAllDiscussionsPage::class),
(new Extend\SimpleFlarumSearch(DiscussionSearcher::class))
->addGambit(TagFilterGambit::class),
(new Extend\SimpleFlarumSearch(TagSearcher::class))
->setFullTextGambit(FullTextGambit::class),
// after
(new Extend\SearchDriver(DatabaseSearchDriver::class))
->addFilter(PostSearcher::class, PostTagFilter::class)
->addFilter(DiscussionSearcher::class, TagFilter::class)
->addMutator(DiscussionSearcher::class, HideHiddenTagsFromAllDiscussionsPage::class)
->addSearcher(Tag::class, TagSearcher::class)
->setFulltext(TagSearcher::class, FulltextFilter::class),
Brainstorm
Most of the changes will be simple pattern replacements, to do that we need to take into account some base behavior/abilities.
Dependencies β
composer.json.require.flarum/*
^2.0 (when not set to*)composer.json.require-dev.flarum/*
^2.0 (when not set to*)Infra β
flarum/framework/.github/workflows/REUSABLE_backend.yml@main
or@1.x
=>@2.x
flarum/framework/.github/workflows/REUSABLE_frontend.yml@main
or@1.x
=>@2.x
Frontend
mithril 2.0 -> 2.2
can't find exact instances of this in the code, but the more common instance is a copy from core of:
before
after
Export Registry
Compat API β
compat API no longer works, instead all modules must be imported
before https://github.com/flarum/framework/blob/1.x/extensions/tags/js/src/forum/compat.js after https://github.com/flarum/framework/blob/2.x/extensions/tags/js/src/forum/forum.ts
Importing Modules β
@flarum/core
imports (must remove/replace). βuseExtensions
must use new import format ofext:
instead βCode splitting β
// after extend('flarum/forum/components/LogInModal', 'oninit', function() {
console.log('LogInModal is loaded');
});
Form
: β// after import Form from 'flarum/common/components/Form';
Filesystem
NullAdapter
ββ
Mailer
Swift_Mailer
& warn about the move from swift mailer to symfony mailer: https://symfony.com/doc/current/mailer.html βJSON:API
Attempt to use advanced steps for this, but likely not possible to do any automated upgrading. warn instead to read:
http://localhost:3000/extend/update-2_0#jsonapi
Search
Gambits (back to front) (produced js gambit based on pattern) β
// after class TagFilter implements FilterInterface { use ValidateFilterTrait;
}
Flarum\Search\AbstractSearcher
=>Flarum\Search\Database\AbstractSearcher
βFlarum\Filter\FilterState
=>Flarum\Search\SearchState
βFlarum\Query
=>Flarum\Search
βFlarum\Filter
=>Flarum\Search\Filter
βLESS β