Git Product home page Git Product logo

arcanist's Introduction

Installation

Arcanist requires at least PHP 8.1 and Laravel 9 or Laravel 10.

composer require laravel-arcanist/arcanist

Documentation

You can find the full documentation here.

Credits

License

MIT

arcanist's People

Contributors

ercsctt avatar erikwittek avatar hguenot avatar ksassnowski avatar thoresuenert avatar ziming avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arcanist's Issues

UnknownStepException

Good Morning,

First off, love the package ๐Ÿ‘๐Ÿป

We noticed that we are encountering an issue with the UnknownStepException being triggered if a user decided to change the step slug within the URL. This is of course intentional but is there a way in which we can capture the error and return a NotFoundHttpException instead or redirect the user back to the first step?

Thanks,
Matthew

How to upload files?

Hi,

I'm experiencing with this package and I have a trouble with file uploading:

  • In WizardAction I'm reading a file field (e.g. avatar) through $payload and i want to do something like Storage::putFile('avatars', $payload['avatar']); to store file in a local storage, but $payload['avatar'] is always an empty array. How to fix that?

Skippable steps

I'd like to use Arcanist to rewrite an existing form that is pretty complicated right now.
I've read the 'getting started' guide on the documentation but I'm still not sure if the package fits my needs: can I use it to write multi-step forms that are also kind of "multi-route"?
To be more clear: my existing form shows/skips some steps based on the data that have been already selected. Is it possible to tell Arcanist to skip a step in a use case like this?

File Upload fields

This is currently just a vague idea that popped into my mind. I think it should be possible to define a Field as an upload or something similar and let Arcanist take care of actually saving the file.

Currently, you would have to implement the process method of the Step to deal with uploaded files. This is something I want to discourage as much as possible and provide built-in solutions to problems that require that escape hatch instead.

The API could look something like this

Field::make('avatar')
    ->file()
    ->saveTo(storage_path('avatars'));

Arcanist could then take care of saving the uploaded file using whatever storage you have configured in your application and store the file path in the avatar key.

This idea could potentially be generalized further to add more behavior to fields.

Repeat option

Hi, is there a way to make a step repeatable? For example, we would have an additional button to save and new

Conditional steps

Hi

Is there a way to have conditional steps

e.g. for a registration process, if one input on the first step say company, then the second step should be different that if the input say private

Optional steps

I've created a POC for optional steps, which extends an omit function on the WizardStep class, which, if returns true, the step is omitted from the wizard at that time. This omit function allows the wizard to be considerably more dynamic, as a step can be omitted based on configurable user state, or even data from previous steps.

Laravel Arcanist fail silently

Have been trying to get this package work for my project for about two days now, have spend the time to read this package and it appears to fail silently at steps validations, what i have discovered is that for some reasons the validation rules for step one is used to validate step two and since step one rules does not match with step two incoming fields it fails and bounce you back without throwing any errors.

For some strange reasons step one forms get submitted successfully after validation and marked as completed in the database, yet when you call iscomplete on step one form it returns false instead of true. i guess thats where the problem starts

Screenshot 2024-04-26 182142

Add artisan command for step/wizard creation

Something to automatically create a new wizard folder in the App\Wizards namespace and steps in App\Wizards\<name>\Steps would be nice.

Proposed commands:
php artisan make:arcanist Registration
Would create a Wizard at App\Wizards\Registration.

php artisan make:arcanist Registration --steps=UsernameAndPasswordStep,AnnoyingNewsletterStep
Would create a Wizard at App\Wizards\Registration if not exists and add two steps.

If you are willing to accept it, I'd contribute it.

Is version 1.0 accessible?

I'm wondering if there's a separate repository or branch for this upcoming version? There appears to be only the main branch for this repository, and I cannot find any other reference to the upcoming 1.0 version - other than it's under development, and coming soon.

Generic wizards

I am really looking forward to using this package! Thanks for making this open source!

I have a few questions, specifically about Livewire. From reading the docs, and a little bit of source diving, I think it will be difficult to support it. The package is pretty opinionated. The concept is great, but I would love to be able to use it generically.

This goes for standard controllers, too. We validate our data in controllers using form requests. It would be cool if we can make them part of a wizard. It would only have set and get data from the wizard, instead of a model for example. Most concepts can stay, a little bit more flexibility in the controller/routes would be very useful, I think. It allows us to stick to what we do, while using the power of your package to deal with all the difficulties of wizards.

Is this something you would consider in the future?

Use the var that passed from action [question]

I need to pass data back to the wizard from the action, in the docs

In case you need to pass data back to the wizard from the action, you can provide an associative array to the success method of the action.

so I'm already did this

return $this->success(['user' => $user]);

but, how to access / get the var in the wizard?

tried this way at wizard, but only get null

$this->data('user');

also tried to dd $this, but can't find the var that passed

[REST API Renderer] Wizard Cancel force redirect Response

First of all we pushed our Renderer to GitHub today:
suenerds/arcanist-rest-api-renderer

We tried to implement a cancel button today and found a hardcoded redirect response in the Wizard destroy method.

Idea for a solution:
You have build a delete hook for clean up purposes.
As we need a way to overwrite the redirect response I want to use the same mechanism for completing the wizard

/**
     * The action that gets executed after the last step of the
     * wizard is completed.
     */
    protected string $onDeleteAction = NullAction::class;


/**
     * Gets called after the last step in the wizard is finished.
     */
    protected function onAfterDelete(ActionResult $result): Response | Responsable | Renderable
    {
        return new JsonResponse([
            'redirect' => [
                'path' => '/wizard/assignments'
            ]
        ]);
    }

 public function destroy(Request $request, string $wizardId): Response | Responsable | Renderable
    {
        $this->load($wizardId);

        $result = $this->actionResolver
            ->resolveAction($this->onDeleteAction)
            ->execute($this->transformWizardData());

        if (!$result->successful()) {
            return $this->responseRenderer->redirectWithError(
                $this->currentStep(),
                $this,
                $result->error()
            );
        }

        $this->wizardRepository->deleteWizard($this);

        return $this->onAfterDelete($result);
    }

The Delete Hook will be an Action Class after that and we can use the onAfterDelete function to do whatever we need to do after Delete.

I will update this issue when my PR is ready.

How to validate an array of objects in wizard step

I am not sure how should I go about validating my data that I am passing as array of objects to my field. I can't make those fields individually because fields are generated dynamically. It's in a questionairre format where I am sending questions from database to front end and sending array of responses with questions id back to Field::make('responses'). Any help will be appreciated

REST API Renderer

Currently there are renderers available for blade templates and Inertia.js (I am not familiar with this, so bare with me). If I have a JavaScript frontend project (Vue, React, Svelte, etc.) that is separate from the Laravel side, how best would I pass the data back and forth? I suppose I could start with WizardStep::viewData, I would just need to dig into the source code and docs a bit more to figure that out. Are there any caveats I should know about?

Migration fails on MySQL 8.0.22

Publishing then running the migrations fails with the following error:

SQLSTATE[42000]: Syntax error or access violation: 1101 BLOB, TEXT, GEOMETRY or JSON column 'data' can't have a default value (SQL: create table `wizards` (`id` int unsigned not null auto_increment primary key, `class` varchar(255) not null, `data` json not null default '[]', `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')

Question about security

Hi,

I'm just getting started with this package but I have one security related question:

When brute forcing the IDs of a wizard it is possible to access pending wizards (from other sessions) which might have stored sensitive data already (like names, addresses or email addresses for example). Is it possible to prevent this behavior?

An example:

  • User A starts a wizard (ID 1) and enters his home address and email address in step 1 and saves.
  • User B opens /wizard/{slug}/1/sensitive-step in his browser and sees the data of User A.

In my opinion the data should be bound to the session (and not to an URL parameter) or the ID should be stored in an encrypted cookie for example if there's no other solution with the current implementation via URL.

Let the discussion begin ๐Ÿ˜„๐Ÿš€

laravel-arcanist/inertia-response-renderer 0.5.0 requires inertiajs/inertia-laravel ^0.4.1 -> found inertiajs/inertia-laravel[v0.4.1, ..., v0.4.5] but it conflicts with your root composer.json require (^0.5.1).

Your requirements could not be resolved to an installable set of packages.

Problem 1
    - Root composer.json requires laravel-arcanist/inertia-response-renderer ^0.5.0 -> satisfiable by laravel-arcanist/inertia-response-renderer[0.5.0].
    - laravel-arcanist/inertia-response-renderer 0.5.0 requires inertiajs/inertia-laravel ^0.4.1 -> found inertiajs/inertia-laravel[v0.4.1, ..., v0.4.5] but it conflicts with your root composer.json require (^0.5.1).

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions

A few questions about how to use the package

Hello
Thanks for your interesting package.

I know the documentation is not complete yet, but I have some questions about how to use the package.

  1. I'm confused about creating view (blade) files and how to specify URLs for action forms, as well as next or previous buttons. Of course, I almost solved this, but I do not know exactly what the best method is, and I hope a clearer example will be given (especially for Blade).

  2. The next question is how to use this form wizard in editing mode? What should we do if we want to edit an entity that has already been created and stored in DB? How to access the desired Model and share it between the various step forms? Especially based on Laravel model binding.

  3. Suppose we have defined a Wizard to register a Post, which consists of several steps (PostWizard), now if on our website it is possible for both regular users and admins (in the admin panel) to insert a post How can we use this PostWizard in both sections? (With different routes)
    For example
    exampl.com/user/wizard/post
    exampl.com/admin/wizard/post

  4. From there, access to the wizard is possible through the ID and the address wizard/example/wizardId, now if one person comes and completes part of a form (for example, wizard number 5) and another person in his own browser enters the desired address Enter (wizard/example/5) seems to have access to information entered by the previous user. Isn't this a problem? Maybe I misunderstood this!

Thank You

How should 404 errors be handled

If I go to a non-existent step in a wizard I get a white page. The network tab shows a 404, but the only mark-up in the source of that page is debugbar. I can see the two exceptions being thrown.

image

A prepareForValidation method

It will be great if there is a prepareForValidation() method just like in Form Request. Will be helpful for checkbox fields especially. Where we want to do a $this->boolean('checkbox_field')

I see that the Field class has a transform() method, but not sure if it is equivalent to Laravel FormRequest's prepareForValidation() as I didn't see it get called before the $this->validate(...) in WizardStep processStep() method

Action payload doesn't include data from the last step

Hi there,

Firstly, I'm having an amazing time playing with this package, thank you for the time & effort you've put in to it!

I noticed that I was getting a 500 error when trying to access data in the payload of my Action class but only on the first time I tried to submit, if I refreshed it worked fine.

I traced this through in the code (AbstractWizard.php) and found that the instance doesn't have access to the updated data yet in processLastStep - I'm assuming it's been persisted but not reloaded/attached to the instance straight away.

I fixed this on the example I'm working with by reloading the wizard after the saveStepData call in the update function.

EDIT: I'm also using the inertia-response-renderer package incase that infromation is helpful

Disclaimer

It's highly likely I'm using this wrong so if I am, I apologise for wasting your time,

Cheers!

Access level to fields() must be public

Hello,

First of all I'd like to say I'm loving Arcanist and the documentation is cheeky and spectacular.

I am currently using Laravel Homestead which has PHP 8 and Laravel 8. The error I get is

2022/01/19 17:03:17 [error] 17605#17605: *746 FastCGI sent in stderr: "PHP message: PHP Fatal error: Access level to App\Wizards\Application\Steps\Step01_BasicInformation::fields() must be public (as in class Arcanist\WizardStep) in /home/vagrant/code/.../app/Wizards/Application/Steps/Step01_BasicInformation.php on line 20PHP message: PHP Fatal error: Access level to App\Wizards\Application\Steps\Step01_BasicInformation::fields() must be public (as in class Arcanist\WizardStep) in /home/vagrant/code/.../app/Wizards/Application/Steps/Step01_BasicInformation.php on line 20" while reading response header from upstream, client: 10.22.33.1, server: app.test, request: "GET /wizard/apply HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "app.test"

I ran into an issue when deploying it today following the documentation here: https://laravel-arcanist.com/getting-started. It shows under the step slug example that the fields functions should be protected as seen below:

protected function fields(): array { return [ // Field::make('field-name') // ->rules(['required']), ]; }

However when doing this I get the error seen above. I followed this over to src/WizardStep.php and modified it from

public function fields(): array { return []; }

to

protected function fields(): array { return []; }

I'm still in the middle of deploying this so I'm not sure what the effects of this are, but it seems to have cleared up the error for now. I'm not quite sure what the correct state should be for the fields function, but I thought I'd pass this along to see if this is user error or a mixup between when the documentation was written and a github revision.

Appreciate the insight and your time.

Testing

Hi

I'm beginning to use this in a project, and it's quite intuitive so far, however, I was wondering how one would go about writing tests for a wizard that's written in this package.

REST API Renderer

As we discussed early in issue #9 (I cannot reopen it), we have one thing left:

To render fields in the frontend SPA we need to access the field list from the Render like this:

public function renderStep(WizardStep $step, AbstractWizard $wizard, array $data = [] ): Response | Responsable | Renderable
    {
        return new JsonResponse([
            'wizard' => $wizard->summary(),
            'step' => $step,
            'fields' => $step->getFields(),
            'formData' => $data,
        ]);
    }

As you see we call a custom function getFields(). We only need this because the fields() function is protected.

Is there any chance to change that to public ?

https://github.com/laravel-arcanist/arcanist/blob/ecb3f51c5b63222f1c40d700218f09699f5b6f14/src/WizardStep.php#L91-94

I opened a PR (#17) to change it.

Inertia support

Hi there, I see this package very useful for something my company is trying to do

Also we're using InertiaJS, it will be very nice to have compatibility with this package like the "Custom renderers" (which seems wip in the docs page) and sharing data will be much easier reusing Inertia's methods.

Actions in steps

Hi

I'm trying to make a new registration Wizard, but I don't want to create user, subscriptions etc. unless the email address is validated, so I was wondering if it is possible to some how send a notification email to the email entered in step 1, then in step two, ask for the verification code and not allow step 3 until the code is received ?

I was hoping to do this via events, but I'm not sure if there a 'Step started event' and the documentation on events is not yet complete :)

arc lint doesnt see all the paths in the directory

When I do an arc lint, I only get 7/100+ files in the directory

Tried different regex for include but cant seem to get it to see everything

arclint file
{ "linters": { "cppcheck": { "type": "cppcheck", "exclude" : [ ], "include": [ "(.*\\.c$)", "(.*\\.h$)" ] } } }

Dependent fields should cascade

Currently, invalidating fields if one of their dependencies changed does not cascade. This means that given I have the following fields

A    -->     B      -->     C
        Depends on A    Depends on B

if A gets changed, B should be invalidated. Since B has now been changed as well, C should also be invalidated.

This is currently not the case. Right now, only B would get invalidated and it would not cascade further.

Overriding registerRoutes (for multilingual support, etc.)

I'm looking at Arcanist for a project which needs to create multilingual routes to support different locales. For example, I'd need something like:

/en/forms/profile/1/about-me
/fr/formulaires/profil/1/a-propos

Is there a way to override the default registerRoutes method to handle multilingual routes? My project uses Laravel Multilingual Routes, but I think any solution to this use case in Arcanist should be as agnostic as possible. Perhaps an option might be to allow an integrator to bypass Arcanist's automatic registration of routes and document the process for creating all necessary routes independently in a routes/arcanist.php file or something like that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.