yanah / laravel-kwik-crud
A Laravel package designed to streamline and accelerate development. Let's make it 'kwik' (quick)
Requires
- php: >=7.4
- laravel/framework: ^8.0|^9.0|^10.0|^11.0
- dev-main
- v1.5.0-beta.2
- v1.5.0-beta
- v1.4.9
- v1.4.8
- v1.4.7
- v1.4.6
- v1.4.5
- v1.4.4
- v1.4.3
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.1
- v1.0.0
- dev-test/from-pr
- dev-refactor/input-wrapper
- dev-feature/autocomplete
- dev-refactor/move-vue-to-package
- dev-feature/configurations
- dev-feature/generate-crud-files
- dev-feature/data-table-upgrade
This package is auto-updated.
Last update: 2025-04-25 03:03:41 UTC
README
Description
This package is built to ease the work developers do by streamlining the process of scaffolding CRUD operations. It integrates seamlessly with Laravel, Inertia, and Vue.js 3, reducing boilerplate and simplifying the creation of CRUD functionality.
Discord
To collaborate, please join here: https://discord.gg/UksAt4HqF9
Overview
- Stack Used
- Installation & Configurations
- Run the application
- Package Command/s
- CRUD Implementation
I. CRUD (Create)
II. CRUD (LIST)
III. CRUD (EDIT/UPDATE)
IV. CRUD (SHOW)
- Customize Pages (CRUD)
Insert Components before / after CRUD Pages (List, Edit, Create)
Customize Form fields (Create/Edit)
- Additional Security
- CRUD Lifecycle
- Overriding CRUD controller method
- Before & After Create (CRUD)
- Before & After Update (CRUD)
Stack Used
- Inertia 2.0
- Vue 3
- Prime Vue 4
- Reactjs (Coming soon)
Installation & Configurations
To install the package, follow these steps:
$ composer require yanah/laravel-kwik-crud
$ php artisan kwik:install
- The default scafold is vuejs. We'll use reactjs soon.
kwik:install --client=reactjs
, Install for reactjs (SOON)
Add KwikServiceProvider
to the providers array in your config/app.php
:
'providers' => [ // Other providers... Yanah\LaravelKwik\KwikServiceProvider::class, ]
In app/Http/Kernel.php
, ensure that the HandleInertiaRequests
middleware is added under web middleware groups.
protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\HandleInertiaRequests::class, // other middlewares... ], ];
Publish kwik configurations
$ php artisan vendor:publish --tag=kwikconfig
After this, new files will be added in config
Install Front-end dependencies:
$ npm install vue@latest @fortawesome/fontawesome-free primevue @primevue/themes primeicons @primevue/forms
In vite.config.js
alias, add @kwik
resolve: { alias: { '@kwik': path.resolve(__dirname, 'vendor/yanah/laravel-kwik-crud/src/client/vuejs'), // use reactjs for react }, },
In tailwind.config.js
alias, add this line.
content: [ // More contents here 'vendor/yanah/laravel-kwik-crud/src/client/vuejs/**/*.vue', ],
Run the application
Check tailwind.config.js
configuration
$ npm run dev
$ php artisan serve
Package Commands
Execute CRUD automatically
$ php artisan kwik:crud {name} {--only=}
Check the flags below:
name
- refers to your model name. It should be capitalized & in singular form.
--only=
:
crudfiles
- Only the ModelList.php, ModelCreate.php, ModelEdit.php will be generatedcontroller
- Only the {Model}Controller will be generatedmodel
- Only the Model will be generate
Example:
$ php artisan kwik:crud Post --only=crudfiles
I. CRUD (Create)
Populate form with fields inside prepareCreateForm()
:
Example:
$this->formgroup->addGroup('users', [ 'tab' => true, 'label' => 'Users', ]); $this->formgroup->addField('first_name', [ 'label' => 'Samuel', 'type' => 'text' ]);In creating of a form, configure `Crud\{Model}Create.php`
First, in prepareCreateForm(), Add group
Use the following syntax to add a group:
$this->formgroup->addGroup('GROUP_NAME_UNIQUE', [ 'tab' => boolean, 'label' => string, ]);
Second, Add field. Here is the syntax:
$this->formgroup->addField('FIELD_NAME', $attributes);
Note: The type
attribute serves as the key to determine what input type we'll implement.
$attributes (Properties)
Types:
- text
- input Group
- textarea
- switch
- checkbox
- radio
- select
- select_group
- calendar: date & time
- autocomplete
- custom_file
- custom_html
**Text** $attributes example: [ 'label' => 'Post Title', 'type' => 'text' ] **Input Group** $attributes example: [ 'type' => 'input_group', 'label' => 'Address', 'placeholder' => 'Type your address', 'group_icon' => 'pi pi-address-book' ] - group_icon is referred here: https://primevue.org/icons/ **Textarea** $attributes example: [ 'label' => 'Post Body', 'type' => 'textarea', 'rows' => 4 ] **Switch** $attributes example: [ 'label' => 'Billing details', 'type' => 'switch' ] **Checkbox** $attributes example: [ 'type' => 'checkbox', 'is_boolean' => true, // if you need to return the checkbox as boolean, else string. 'value' => old('CHECKBOX_ITEM', false), 'label' => 'Your label', 'class_item' => 'mb-5' ] **Radio** $attributes example: [ 'label' => 'Business Options', 'type' => 'radio', 'options' => [ ['label' => 'Option 1', 'value' => 'option1'], ['label' => 'Option 2', 'value' => 'option2'], ['label' => 'Option 3', 'value' => 'option3'], ] ] **Select** $attributes example: [ 'label' => 'Business category', 'type' => 'select', 'options' => [ ['label' => 'Option 1', 'optionValue' => 'option1'], // note: optionValue should be string ['label' => 'Option 2', 'optionValue' => 'option2'], ['label' => 'Option 3', 'optionValue' => 'option3'], ] ] **Select Group** $attributes example: [ 'type' => 'select_group', 'label' => 'Service Group', 'placeholder' => 'List of Services', 'required' => true, 'options' => [ [ 'label' => 'First group', 'items' => [ [ 'label' => 'First1', 'optionValue' => 'first1'], // note: optionValue should be string [ 'label' => 'First2', 'optionValue' => 'first2'], [ 'label' => 'First3', 'optionValue' => 'first3'], ], ], ] ]; **Calendar** $attributes example: [ 'label' => 'business Calendar', 'type' => 'calendar' ] To set time only, configure inputProps: [ 'type' => 'calendar', 'label' => 'Time only', 'inputProps' => [ 'timeOnly' => true, 'hourFormat' => '12' ] ] See more attributes here: https://primevue.org/datepicker/#time **Custom html** - If you wan to add a custom html: [ 'type' => 'custom_html', 'value' => function() { return '<div class="text-3xl border-t pt-4 mb-5">Read here.</div>'; } ]
Autocomplete input
Example:
[ 'type' => 'autocomplete', 'required' => true, 'label' => 'Search me', 'default_query_results' => [ ['label' => 'test', 'value' => 'this'], ['label' => 'test2', 'value' => 'this2'], ], 'api_endpoint' => '/post/search' ]
Property | Type | Description |
---|---|---|
default_query_results |
array |
Automatically populates values to be searched if an API fetch is not required. |
api_endpoint |
string | null |
Defines the API endpoint. You should have a /post/search route to handle the request and then the response must match the data structure of default_query_results . |
Creating custom vue file
Add custom vue file into the field.
[ 'type' => 'custom_file', 'source' => '@/Components/CustomVueFile.vue' // This is relative to resources/js/Components directory ]
source
- All fileds should be saved insideComponents
folder.
Props:
attributes
- All of the array values above will serve as attributes.
Emit
@updateFieldValue
- This will update the value and be passed as payload.
Example:
<template> <label>Input Something</label> <input @input="updateInput" :class="`border-gray-300 shadow-sm focus:ring-primary-default focus:border-primary-default p-2 w-full`" /> </template> <script setup> const props = defineProps({ attributes: Object, fieldName: String }) const emit = defineEmits(['updateFieldValue']); function updateInput(event) { emit('updateFieldValue', props.fieldName, event.target.value); } </script>
More Attributes:
[ 'helper_text' => 'Sample text', 'value' => 'ANY', // we attached this for every field for edit page purposes. 'wrapperProps' => [ // We may add bind to the wrapper of label & input // example: 'class' => 'bg-danger flex-row' ], 'labelProps' => [ // Cutomize or add styles on label // example: 'class' => 'text-sm' ], 'inputProps' => [ // Cutomize or add styles on Input Fields // example: 'class' => 'bg-danger w-full' ], 'tooltip_label' => 'You may want to add tooltip for label. Icon is question mark.' ]
(To customize fields proceed to the bottom.)
*** Validations ***
Validations are defined in $validationRules
.
protected $validationRules = [ // Add validations here. ];
II. CRUD (LIST)
CRUD List is configured in Crud\{Model}List.php
A. Two options how we display the table
First, Through Pagination.
Use BodyPaginatorInterface
as interface, then add the responseBodyPaginator()
.
It should look like this:
class {Model}List implements ControlCrudInterface, BodyPaginatorInterface { public function responseBodyPaginator(Builder $query) : LengthAwarePaginator { // you may customize the query here. return $query->paginate($this->perPage); } }
Second, We may want to display all response data.
Use BodyCollectionInterface
as interface, then add the responseBodyCollection()
It should look like this:
class {Model}List implements ControlCrudInterface, BodyCollectionInterface { public function responseBodyCollection(Builder $query) : Collection { return $query->get()->map(function($item) { $item->primary = $item->title; // customized main text $item->secondary = $item->body; // description return $item; }); } }
or, you may customize the row using html codes by adding rawHtml
.
public function responseBodyCollection(Builder $query) : Collection { return $query->get()->map(function($item) { $item->rawHtml = '<div class="text-xl">Custom html here</div>'; // Add this property return $item; }); }
B. Define View
We have two options of how our list should look like:
ListTemplateViewEnum::TABLELIST
or ListTemplateViewEnum::LISTITEM
- First,
TABLELIST
view contains pagination which requiresBodyPaginatorInterface
interface. - Second,
LISTITEM
view displays all list it is attached toBodyCollectionInterface
.
C. Toggle Visibility
In your \App\CrudKwik\DIR\{Model}List.php
file, insert toggleVisibility
method
use Yanah\LaravelKwik\Crud\CrudListControl; public function toggleVisibility(CrudListControl $control) : array { $control->set('showSearch', true); // add more below return $control->get()->toArray(); }
To toggle action buttons:
$control->set('showSearchBar', false); $control->updateAction('edit', true); $control->updateAction('delete', true);
APIs:
showSearchBar
: boolean - wrapper of add button, search and summaryshowSearch
: boolean - toggle display search inputshowPrintPdf
: boolean - toggle pdf print button (WIP)showAddButton
: boolean - toggle Add buttonshowListSummary
: boolean - This shows the summary list of records in table listactions
: array - toggle action buttons (preview, edit, delet).
Available toggle controls:
'showSearchBar' => true, 'showSearch' => true, 'showPrintPdf' => false, 'showAddButton' => true, 'showListSummary' => true, 'actions' => [ 'preview' => true, 'edit' => true, 'delete' => true, ]
D. Handle Search functionality
Search functionality is visible only on pagination list and $control->set('showSearch', true);
public function search(Builder $query, string $q) : Builder { return $query->where('FIELD', $q); }
III. CRUD (EDIT/UPDATE)
We'll reuse the fields we defined in prepareCreateForm()
.
We update those in prepareEditForm()
.
$this->formgroup->editField('GROUP_NAME', 'FIELD_NAME', $attributes); // pattern
For $attributes
, refer to $attributes (Properties) above.
Example:
$this->formgroup->editField('details', 'post_title', [ 'label' => 'Post Title (Edited)', 'value' => old('post_title', $post->title) ]);
Or the details:
$this->formgroup->editDetails(string $groupName, array $details);
(To customize fields proceed to the bottom.)
*** Validations ***
Check method getValidationRules
to modify validations added in {Model}Create.php
public function getValidationRules() {}
IV. CRUD (SHOW)
From your controller, customize the display based on the data.
Expected return:
[ 'data' => $data, // This will be shown on the table 'except' => [] // list down the fields you don't want to display. ];
Customization:
You may add vue files before or after the table:
public function getShowItem(Builder $query, $fields = ['*'], $id) { $this->setPageWrapperItems([ 'prepend' => '@/Components/SampleLorem.vue', // Before the table 'append' => '@/Components/SampleLorem.vue', // This will be shown after the table ]); // More codes below }
<script setup> const emit = defineEmits(['toggleShowTable']); // add this </script>
Customize Pages (CRUD)
Insert Components before / after CRUD Pages (List, Edit, Create)
Implement PageAffixInterface
in Crud\{Model}Create.php
, Crud\{Model}Edit.php
, Crud\{Model}List.php
and define the components to be inserted (prepend / append).
use Yanah\LaravelKwik\App\Contracts\PageAffixInterface; class {CrudClass} extends KwikForm implements PageAffixInterface { public function defineAttributes(): array { return [ 'prepend' => '@/Components/YOUR_FILE_HERE.vue', 'append' => '@/Components/YOUR_FILE_HERE.vue' ]; } }
prepend
& append
have available api:
import { usePage } from '@inertiajs/vue3'; const { props: pageProps } = usePage(); console.log(pageProps.pageWrapper);
Example:
//@/Components/YOUR_FILE_HERE.vue const emit = defineEmits(['updateCrudList']); // Make sure to define updateCrudList. const ChangeListItems = () => { router.visit(`URL`, { method: 'get', preserveState: true, replace: true, onSuccess: (response) => { emit('updateCrudList', response.props.crud) }, }); }
Customize Form fields (Create/Edit)
You may want to wrap fields.
Example:
$this->formgroup->beginWrap('INDEX_KEY', $atributes, $headings); // Add Fields here $this->formgroup->endWrap();
See $attributes
below:
[ 'class' => 'gap-4 xs:grid-cols-1 sm:grid-cols-1', // cuztomize the cols number as desired 'style' => 'background:red;' ]
See $headings
(optional) below:
[ 'heading' => string, 'paragraph' => string, ]
Additional Security
Notice that in show
& edit
pages, routes are accessible via id.
You may want to append uuid
instead.
First, make sure to add uuid
field in your model and migration.
Next, use the UuidRestrictionTrait
trait in your controller.
Example:
use Yanah\LaravelKwik\Traits\UuidRestrictionTrait; class {Your}Controller extends KwikController implements PageControlInterface { use UuidRestrictionTrait; // Attach this }
CRUD Persist Lifecycle
Store
- PageControl - Serves as middleware.
beforeStore
- prepare method before storing.- Validations - handle validations.
- Insert Model - updateOrCreate or create
afterStore
- Handle . We may trigger an event after store.
Update
- PageControl - Serves as middleware.
beforeUpdate
- prepare method before storing.- Validations - handle validations.
- Update model
afterUpdate
- Handle . We may trigger an event after store.
Overriding CRUD controller method
You may want to override Crud Controller methods and use Laravel CRUD methods:
class YourController extends KwikController implements PageControlInterface { public function create() { // do something here. return parent::create(); } }
Before & After Create (CRUD)
In some cases, you may want to execute something or trigger an event before and after creating
of new record. To do this, you have to override beforeStore()
and afterStore()
methods.
In your \App\CrudKwik\DIR\{Model}Create.php
file, insert these lines:
use Yanah\LaravelKwik\Services\CrudService; public function beforeStore(CrudService $crudService) : void { // Change to false if you want to insert validated payloads only. $crudService->setShouldIncludeFillable(true); $crudService->setIndexOfUpdateCreate([ // You may want to use updateCreate. // Add here the index, example: 'user_id' => 1 // this will updateCreate based on user_id ]); } public function afterStore($response) { // Add stuffs // response return response()->json(['success' => true], 201); }
Before & After Update (CRUD)
In your \App\CrudKwik\DIR\{Model}Edit.php
file, insert these lines:
use Yanah\LaravelKwik\Services\CrudService; public function beforeUpdate(CrudService $crudService) : void { $crudService->setShouldIncludeFillable(true); $crudService->setIndexOfUpdateCreate([ // You may want to use updateCreate. // Add here the index ]); } public function afterUpdate($id) { // trigger event after update return response()->json(['success' => true], 201); }
Todo list:
- Add Test
- Responsiveness
- Validate frontend
That's all. Please feel free to send PR when you found a bug.
Hope this package will help you "kwik"en your development. Appreciated!