Important {.alert.alert--info} This feature is currently unstable and these docs are outdated. Some or all of the features described below may not work at the moment.
What does "extending packages" mean?
Most of the time, Hiker Packages (or packages built for Laravel in general) provide useful features you can get started with right away. However, sometimes the default behavior provided by these packages does not cover all your needs. What should you do in those cases? Creating a new package from scratch that would match your exact needs could be a lot of work, that's why it could be a good idea to be able to adapt the parts of the existing package that do not match your application's objectives. That what we call "extending packages".
As a package maintainer, you should always keep flexibility in mind. If you want your audience to love your package, you should let them adapt it slightly to their needs. Our Trail & Hiker packages provide the tools you need to get started with such a package, but keep in mind that most of the important aspects will come from your development methodology. A simple way to go is to ask yourself "What if someone wanted to change this?" each time you make an important code decision.
Extending vendor Resources
Resources defined in third-party Hiker packages are registered using the Hiker::resourcesIn()
method, which will automatically check for any existing Resources with the same key
in your application's app/Hiker/Resources
directory. This will allow you to extend vendor-defined Resources and their flows, simply by defining these Resources in your own working directory:
namespace App\Hiker\Resources\Pages; // The vendor-defined resource we want to extend use Hiker\Cms\Resources\Pages\Page as Resource; class Page extends Resource { // ... }
Of course, now we'll also have to replace the Resource's flows repository in the same way:
namespace App\Hiker\Resources\Pages; // The vendor-defined flows repository we want to extend use Hiker\Cms\Resources\Pages\PageFlows as FlowsRepository; class PageFlows extends FlowsRepository { public function create() { return parent::create() ->run(Nodes\SomeExtraNode::class); } }
Manipulating existing flows
Inside the extended flow
methods, you probably don't want to re-define the package's whole Roadmap. In fact, you should avoid extra maintainance by performing as few changes as possible. This is possible by calling one of these 3 helpful methods:
- swap
- before
- after
These will allow easier flow customizations:
class PageFlows extends FlowsRepository { public function create() { return parent::create() ->swap(Nodes\DoingStuff::class, fn($roadmap) => $roadmap->run(Nodes\DoingSomethingElse::class)) ->before(Nodes\SaveModel::class, fn($roadmap) => $roadmap->run(Nodes\GenerateSomeAttributeValue::class)) ->after(Nodes\SaveModel::class, fn($roadmap) => $roadmap->run(Nodes\SendEmail::class)); } }
In these examples we only insert one new action at the time, but the roadmap manipulations can perform multiple insertions at once:
class PageFlows extends FlowsRepository { public function create() { return parent::create() ->swap(Nodes\DoingStuff::class, function ($roadmap) { $roadmap->run(Nodes\DoingSomethingElse::class) ->run(Nodes\DoingAnotherThing::class) ->run(Nodes\DoingAFinalThing::class); }); } }
By default, each occurrence of $node
will be subject to the roadmap manipulation provided by $replacement
. However, it is possible to handle each of them separately:
class PageFlows extends FlowsRepository { public function create() { return parent::create() ->before(Nodes\DoingStuff::class, function ($roadmap, $occurrence) { if ($occurrence === 0 || $occurrence === 2) { $roadmap->run(Nodes\DoingSomethingElse::class) } else { $roadmap->run(Nodes\DoingAnotherThing::class) } }); } }
For convenience, it is also possible to directly specify which occurrence should be handled (starting at 0
):
class PageFlows extends FlowsRepository { public function create() { return parent::create() ->after(node: Nodes\DoingStuff::class, occurrence: 0, replacement: fn ($roadmap) => $roadmap->run(Nodes\DoingSomethingElse::class)) ->after(node: Nodes\DoingStuff::class, occurrence: 1, replacement: fn ($roadmap) => $roadmap->run(Nodes\DoingAnotherThing::class)); } }