Acciones CRUD


Es común las acciones de crear, editar y eliminar registros con el objetivo de facilitar estas acciones se cuenta la la opción de usar el siguiente trait en los componentes de livewire.

Uso de Trait en componente

Para hacer uso del trait AccionesCrud debemos especificar en el componente de livewire.

use Livewire\Component;
use DevCucei\RocketmanComponents\Traits\Views\WithActionsCrud;

class Ejemplo extends Component
{
    use WithActionsCrud;

}

Variables publicas

Es necesario declarar las siguientes variable publicas en el componente de livewire para su uso posterior.

    /**
     * Variables para uso de crud
     * @var
     */
    public $formularioAttributes;
    public $mode,$formulario;

Permisos

Spatie permission nos permite asociar a nuestros usuarios roles y permisos. Para permitir realizar acciones de crud a los usuarios, se requiere especificar en el componente de livewire como un permiso que se aplicara a todas las acciones,

    /**
     * Indica permiso para acciones de crud
     */
    public  $permission = 'administrar.roles';

si es necesario mas de un permiso

    /**
     * Indica permisos para acciones de crud
     */
    public  $permission = 'administrar.roles|administrar.permisos';

o pemisos especificos para cada acción.

    /**
     * Indica permisos para acciones de crud
     */
    public  $permissionCreate = 'administrar.roles';
    public  $permissionDelete = 'administrar.roles';
    public  $permissionUpdate = 'administrar.roles';

Para usar los permisos crea un nuevo metodo en el modelo User.php que valide si el usuario cuenta con el permiso asignado atraves de un rol

    public function getPermissionSession($permission){
        $roles = $this->roles;
        foreach($roles as $role){
            if($role->hasPermissionTo($permission)){
                return true;
            }
        }
        return false;
    }

Validaciones

{info} El uso del Trait no interviene con la estructura estándar de las validaciones en Livewire

protected $rules = [
'name' => 'required|min:6',
'email' => 'required|email',
];

Sobreescritura funciones de Trait

En ocasiones las funciones del Trait no serán suficientes por lo que podremos realizar la Sobreescritura nombrando en el componente de Livewire una función con el mismo nombre.

Renombrar funciones de Trait

Si es neceaario agregar lineas de código para el uso funciones del trait podrás renombrar la función y llamarla de nuevo en el componente de Livewire.


    /**
     * Renombra función de trait para utilizar dos funciones
     */
    use AccionesCrud{
        save as traitSave;
    }

     public function save()
    {
        $this->traitSave(); //función save de Trait acciones crud

    }

Modales y notificaciones

Los modales y notificaciones utilizados para los formularios son componentes de blade que deberan de ser incluidos en la vista del componente de livewire.

    <div>
        <!-- BEGIN: Funcionalidades CRUD-->
            <x-acciones-crud.modal-crud/>
            <x-acciones-crud.modal-delete/>
        <!-- END: Funcionalidades CRUD -->
    </div>

{info}Para dar estilos a los modales podra agrarlo como un attributo

     <div>
        <x-acciones-crud.modal-crud staticBackdrop="true"/>
    </div>

Para hacer uso de las notificaciones agrege al achivo layout del proyecto

    <body> 
        @include('partials.notifications')
        <!---------- toastify-js ----------->
        @include('snippets.toastify-js')
    </body> 

Si incluye mas de un componente de crud en una vista es necesario declarar una variable publica con el id del modal para que Livewire pueda acceder a ellos

    /**
     * @var int Indica id de modal crud y modal delete
     */
    public $modalCrudName = 'modal-crud-giros';
    public $modalDeleteName = 'modal-delete-giros';

Acciones CRUD

Create

Para activar el modal de crear podrás hace uso del componente <x-button-primary> en cualquier lugar de la vista del componete de livewire.

    <x-button-primary 
        wire:click="create()" 
        icono="fa-solid fa-plus" 
        titulo="Agregar"
    />

{info} En caso de que se requiera especificar de otra manera en la vista recuerda agregar wire:click="create()" para seguir haciendo uso de las funcionalidades del trait.

Editar y eliminar

Para activar el modal de editar y eliminar podrás hace uso del componente <x-acciones-crud> o <x-acciones-crud-dropdown> en cualquier lugar de la vista del componete de livewire.

    <x-acciones-crud id="{{$id}}"/>

    <x-acciones-crud-dropdown id="{{$id}}"/>

Ejemplo utilizando trait de llistado

    /**
     * Indica las columnas del listado
     * @var array
     */
    public function getColumns(): array
    {
        return [
            'Acciones' => [
                'view' => [
                    'name'=>'Components.acciones-crud',
                    'attributes' => [
                        'id' => 'id',
                    ],
                ],
            ],
        ];
    }

{info} En caso de que se requiera especificar de otra manera en la vista recuerda agregar wire:click="edit($id)" y wire:click="delete($id)" para seguir haciendo uso de las funcionalidades del trait.

Campos de formulario

Para crear el formulario los campos deberán de ser especificados en el componente de livewire a manera de arreglo dentro de la función publica getFormularioAttributes().

    /**
     * Indica los campos del formulario
     * @var array
     */
    public function getFormularioAttributes(): array
    {
        return [
        ];

    }

Todos los campos cuentan con las misma estructura:

name = Nombre del input.

required = Indica si el input es requerido (true o false).

label = Texto que se mostrara en la etiqueta.

type = Tipo de input (text, textarea, select, date, datetime-local, switch, vertical-checkbox, horizontal-checkbox, vertical-radio, horizontal-radio)

middleware = Indica el permiso o rol para mostrar el campo en el formulario Opcional.

style = Indica el numero de columnas que tomara el input por defecto tomara todas las columnas Opcional.

placeholder = Indica el texto provisional para los inputs de tipo text y text-area Opcional.

value = Indica el valor provisional para los inputs de tipo date y datetime-local Opcional.

a excepción de los inputs con opciones multiples a los cuales se les debera especificar

options = Indica las opciones disponibles puede ser un arreglo o colección,

optionsValue = Indica el campo del arreglo o colección que sera utilizado como valor del input Opcional por default id

labelOptions = Indica el campo del arreglo o colección que sera utilizado como valor del label Opcional por default name

styleOptions = Indica el numero de columnas que tomara cada opción Opcional por default mt-2 mx-2 col-span-4 lg:col-span-4

Ejemplos

Text

    'text' => [
                'name' => 'formulario.name',
                'label'=>'Permiso',
                'type'=>'text',
                'placeholder'=>'permiso',
                'middleware' => 'Empresa',
                'style' => 'col-span-6 lg:col-span-6 p-2',
            ],

Textarea

    'textarea' => [
                'name' => 'formulario.name',
                'label'=>'Permiso',
                'type'=>'textarea',
                'placeholder'=>'permiso',
                'middleware' => 'Empresa',
                'style' => 'col-span-6 lg:col-span-6 p-2',
            ],

Select

    'select' => [
                'name' => 'roles',
                'required' => false,
                'label'=>'Roles',
                'type'=>'select',
                'options' => Role::all()->pluck('name','id'),
                'selected-options' => Role::all()->pluck('name','id'),
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2',
            ],

Date

    'date' => [
                'name' => 'formulario.name',
                'label'=>'Permiso',
                'type'=>'date',
                'value'=>'10/02/2022',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Datatime local

    'datetime-local' => [
                'name' => 'formulario.name',
                'label'=>'Permiso',
                'type'=>'datetime-local',
                'value'=>'10/02/2022',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Switch

    'switch' => [
                'name' => 'formulario.name',
                'label'=>'switch',
                'type'=>'switch',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Checkbox

    'checkbox' => [
                'name' => 'formulario.habilitado',
                'label'=>'Habilitado',
                'type'=>'checkbox',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Checkbox vertical

    'roles-check-vertical' => [
                'name' => 'roles',
                'label'=>'Roles',
                'type'=>'vertical-checkbox',
                'optionsValue' => 'name', //opcional por default name y id
                'optionsLabel' => 'id',
                'options' => Role::all(),
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Checkbox horizontal

    'roles-check-horizontal' => [
                'name' => 'roles',
                'label'=>'Roles',
                'type'=>'horizontal-checkbox',
                'optionsValue' => 'name', //opcional por default name y id
                'optionsLabel' => 'id',
                'options' => Role::all(),
                'styleOptions' => 'mt-2 mx-2 col-span-2 lg:col-span-2',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Radio vertical

    'roles-radio-vertical' => [
                'name' => 'roles',
                'label'=>'Roles',
                'type'=>'vertical-radio',
                'optionsValue' => 'name', //opcional por default name y id
                'optionsLabel' => 'id',
                'options' => Role::all(),
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Radio horizontal

    'roles-radio-horizontal' => [
                'name' => 'roleds',
                'label'=>'Roles',
                'type'=>'horizontal-radio',
                'optionsValue' => 'name', //opcional por default name y id
                'optionsLabel' => 'id',
                'options' => Role::all(),
                'styleOptions' => 'mt-2 mx-2 col-span-2 lg:col-span-2',
                'middleware' => 'Desarrollador',
                'style' => 'col-span-6 lg:col-span-6 p-2'
            ],

Trait

Create

    /**
     * Carga los atributos del formulario.
     *
     * @return
     */
    public function create()
    {
        $this->resetInput();

        $this->mode = 'Crear';
        $this->formularioAttributes = $this->getFormularioAttributes();

        $this->dispatchBrowserEvent('open-modal', ['modal' => 'modal-crud']);
    }

Save

    public function save()
    {
        $this->hasPermission($this->permissionCreate ?? $this->permission);

        $this->validate();

        $instance = $this->model::Create($this->formulario);
        $instance->save();

        $this->resetInput();
        $this->dispatchBrowserEvent('close-modal', ['modal' => 'modal-crud']);
        $this->dispatchBrowserEvent('success-notification-toggle');

    }

Edit

    /**
     * Carga los atributos del formulario y el registro a editar.
     *
     * @return
     */

    public function edit($id)
    {
        $this->resetInput();

        $this->mode = 'Editar';
        $this->formularioAttributes = $this->getFormularioAttributes();
        $this->formulario = $this->model::findOrFail($id);

        $this->dispatchBrowserEvent('open-modal', ['modal' => 'modal-crud']);
    }

Update

    public function update()
    {
        $this->hasPermission($this->permissionUpdate ?? $this->permission);
        $this->validate();

        $this->formulario->save();

        $this->resetInput();
        $this->dispatchBrowserEvent('close-modal', ['modal' => 'modal-crud']);
        $this->dispatchBrowserEvent('success-notification-toggle');

    }

Delete

    public function delete($id)
    {
        $this->hasPermission($this->permissionDelete ?? $this->permission);

        $this->resetInput();
        $this->mode = 'Eliminar';

        $this->formulario = $this->model::findOrFail($id);
        $this->dispatchBrowserEvent('open-modal', ['modal' => 'modal-delete']);

    }

Destroy

    public function destroy()
    {
        $this->formulario->delete();
        $this->resetInput();

        $this->dispatchBrowserEvent('close-modal', ['modal' => 'modal-delete']);
        $this->dispatchBrowserEvent('success-delete-notification-toggle');

    }

hasPermission

    public function hasPermission($permission)
    {
        if(!$this->user->can($permission)) abort(403);
    }