Skip to content

Feature/refactor crud2 #835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 63 commits into from
Nov 23, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
48d0dc5
making crud work
romaninsh Nov 7, 2019
306c4a8
fixes
romaninsh Nov 7, 2019
267e0de
integrated crud into actions
romaninsh Nov 7, 2019
5bb2ce3
Apply fixes from StyleCI
romaninsh Nov 7, 2019
b0a4524
init
ibelar Nov 4, 2019
dee08b4
Code review
ibelar Oct 31, 2019
1ce4176
update comment
ibelar Oct 31, 2019
78aa0aa
Apply fixes from StyleCI
romaninsh Oct 31, 2019
bd1907d
test
ibelar Nov 1, 2019
21e39d7
fix test uri for jsactions.php demo
ibelar Nov 1, 2019
94ee5f1
merge changed
ibelar Nov 4, 2019
95fc5a0
Apply fixes from StyleCI
romaninsh Nov 4, 2019
267b323
update View::on()
ibelar Nov 4, 2019
173e92c
merge
romaninsh Nov 11, 2019
e38e0c0
updated
ibelar Nov 6, 2019
966747c
Apply fixes from StyleCI
romaninsh Nov 6, 2019
13826e2
fix typo
ibelar Nov 6, 2019
193522d
update method name
ibelar Nov 7, 2019
3517bd8
improve functionality and demos
ibelar Nov 7, 2019
dafb10a
Apply fixes from StyleCI
romaninsh Nov 7, 2019
9ecc0d8
improve demo
ibelar Nov 7, 2019
d4fd635
improve demo
ibelar Nov 7, 2019
9ed71c6
Apply fixes from StyleCI
romaninsh Nov 7, 2019
fd128a2
improve demo
ibelar Nov 7, 2019
bb3f7a3
crud improvements
romaninsh Nov 11, 2019
31ae5d0
wip
romaninsh Nov 11, 2019
fc674ff
wip
romaninsh Nov 11, 2019
7c7c52b
Apply fixes from StyleCI
romaninsh Nov 11, 2019
1c67e10
Merge remote-tracking branch 'origin/develop' into feature/refactor-c…
romaninsh Nov 11, 2019
7bb38ca
Merge branch 'feature/refactor-crud2' of github.com:atk4/ui into feat…
romaninsh Nov 11, 2019
3755e3c
action test
ibelar Nov 11, 2019
7e1cef7
Apply fixes from StyleCI
romaninsh Nov 11, 2019
7572d0c
test with getting action
ibelar Nov 12, 2019
3c588d9
Apply fixes from StyleCI
romaninsh Nov 12, 2019
70695a9
change property name
ibelar Nov 12, 2019
17befb7
setup executor from action
ibelar Nov 12, 2019
c0003cf
Apply fixes from StyleCI
romaninsh Nov 12, 2019
8a713d9
code cleanup
ibelar Nov 13, 2019
eea8fc3
refactor and review
ibelar Nov 13, 2019
8415152
Apply fixes from StyleCI
romaninsh Nov 13, 2019
9ffecb9
clean up
ibelar Nov 13, 2019
89aa909
Merge branch 'feature/refactor-crud2' of https://github.com/atk4/ui i…
ibelar Nov 13, 2019
8ad17d4
add hook callback to crud
ibelar Nov 13, 2019
ac31d8c
Apply fixes from StyleCI
romaninsh Nov 13, 2019
40c6a38
adding native action dropdown support into crud
romaninsh Nov 13, 2019
9f1db0f
Apply fixes from StyleCI
romaninsh Nov 13, 2019
113db0a
update demo to contain example of redefining action executor
romaninsh Nov 13, 2019
d77dc1a
Apply fixes from StyleCI
romaninsh Nov 13, 2019
3241b97
Added two really nice demo pages (index and actions)
romaninsh Nov 14, 2019
f06a182
Merge branch 'feature/refactor-crud2' of github.com:atk4/ui into feat…
romaninsh Nov 14, 2019
658651c
Apply fixes from StyleCI
romaninsh Nov 14, 2019
7a43651
fixed and enhancement
ibelar Nov 14, 2019
29ca167
fix action in wizrd
ibelar Nov 14, 2019
13c9262
add action to menu item
ibelar Nov 14, 2019
575c2b0
add UserConfirmation
ibelar Nov 14, 2019
cba1e69
Apply fixes from StyleCI
romaninsh Nov 14, 2019
9d2d94b
hide modal content while reloading
ibelar Nov 15, 2019
6acfa14
refactor
ibelar Nov 15, 2019
d42b07f
apply sorting when using action
ibelar Nov 20, 2019
e1920f6
Apply fixes from StyleCI
romaninsh Nov 20, 2019
16b9206
remove previous test
ibelar Nov 20, 2019
1c96295
remove tutorial from actions page
ibelar Nov 21, 2019
0dd35ed
fix double factory
ibelar Nov 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions demos/crud.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@

require 'init.php';
require 'database.php';
$m = new Country($db);
//$m->getAction('edit')->system =true;
//$m->getAction('delete')->system =true;

$g = $app->add(['CRUD', 'ipp'=>5]);
$g->setModel(new Country($db));
$g->setModel($m);

// callback for model action edit form.
$g->onEditAction(function ($form) {
$form->js(true, $form->getField('name')->jsInput()->attr('readonly', true));
});

// callback for model action add form.
$g->onAddAction(function ($form) {
$form->js(true, $form->getField('iso')->jsInput()->val('WW'));
});

// callback for both model action edit and add.
$g->onAction(function ($form, $ex) {
$form->onSubmit(function ($f) use ($ex) {
return [$ex->hide(), new \atk4\ui\jsToast('Submit all right! This demo does not saved data.')];
});
});

$app->add(['ui'=>'divider']);

Expand All @@ -16,13 +36,13 @@
$crud = $cc->add([
'CRUD',
//'fieldsCreate' => ['name', 'iso', 'iso3', 'numcode', 'phonecode'], // when creating then show more fields
'fieldsDefault'=> ['name'], // when updating then only allow to update name
'displayFields'=> ['name'], // when updating then only allow to update name
'editFields' => ['name', 'iso', 'iso3'],
'ipp' => 5,
'paginator' => ['range'=>2, 'class'=>['blue inverted']], // reduce range on the paginator
'menu' => ['class'=>['green inverted']],
'table' => ['class'=>['red inverted']],
]);

// Condition on the model can be applied on a model
$m = new Country($db);
$m->addCondition('numcode', '<', 200);
Expand Down
25 changes: 11 additions & 14 deletions src/ActionExecutor/UserAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,17 @@ protected function doFields(View $modal)
$this->jsSetSubmitBtn($modal, $f, $this->step);
$this->jsSetPrevHandler($modal, $this->step);

$f->onSubmit(function ($f) {
// collect fields.
$form_fields = $f->model->get();
foreach ($this->action->fields as $key => $field) {
$this->actionData['fields'][$field] = $form_fields[$field];
}
if (!$f->hookHasCallbacks('submit')) {
$f->onSubmit(function ($f) {
// collect fields.
$form_fields = $f->model->get();
foreach ($this->action->fields as $key => $field) {
$this->actionData['fields'][$field] = $form_fields[$field];
}

return $this->jsStepSubmit($this->step);
});
return $this->jsStepSubmit($this->step);
});
}
}

/**
Expand Down Expand Up @@ -391,10 +393,6 @@ protected function jsGetExecute($obj, $id)
{
$success = is_callable($this->jsSuccess) ? call_user_func_array($this->jsSuccess, [$this, $this->action->owner, $id]) : $this->jsSuccess;

// if (is_array($success) || $success instanceof jsExpressionable) {
// return $success;
// }

return [
$this->hide(),
$this->hook('afterExecute', [$obj, $id]) ?:
Expand Down Expand Up @@ -520,8 +518,7 @@ protected function setFormField(Form $form, array $fields, string $step) :Form
foreach ($fields as $k => $val) {
$form->getField($k)->set($val);
}

$form->hook('onStep', [$step]);
$this->hook('onStep', [$step, $form]);

return $form;
}
Expand Down
190 changes: 125 additions & 65 deletions src/CRUD.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,100 +14,88 @@
*/
class CRUD extends Grid
{
/** @var array of fields to show */
public $fieldsDefault = null;
/** @var array of fields to display in Grid */
public $displayFields = null;

/** @var array of fields to show in grid */
public $fieldsRead = null;
/** @var array of fields to edit in Form */
public $editFields = null;

/** @var array Default action to perform when adding or editing is successful * */
public $notifyDefault = ['jsNotify', 'content' => 'Data is saved!', 'color' => 'green'];
/** @var array Default notifier to perform when adding or editing is successful * */
public $notifyDefault = ['jsToast', 'settings'=> ['message' => 'Data is saved!', 'class' => 'success']];

/** @var array Action to perform when adding is successful * */
public $notifyCreate = null;
/** @var string default js action executor class in UI for model action. */
public $jsExecutor = jsUserAction::class;

/** @var array Action to perform when editing is successful * */
public $notifyUpdate = null;
/** @var string default action executor class in UI for model action. */
public $executor = UserAction::class;

/**
* Sets data model of CRUD.
*
* @param \atk4\data\Model $m
* @param array $defaultFields
* @param array $fields
*
* @throws Exception
* @throws \atk4\core\Exception
*
* @return \atk4\data\Model
*/
public function setModel(\atk4\data\Model $m, $defaultFields = null)
public function setModel(\atk4\data\Model $m, $fields = null)
{
if ($defaultFields !== null) {
$this->fieldsDefault = $defaultFields;
if ($fields !== null) {
$this->displayFields = $fields;
}

parent::setModel($m, $this->fieldsRead ?: $this->fieldsDefault);
parent::setModel($m, $this->displayFields);

$this->model->unload();

foreach ($m->getActions(Generic::SINGLE_RECORD) as $single_record_action) {
if ($single_record_action->short_name === 'edit') {
// if edit then this executor is ok.
$executor = $this->owner->factory($single_record_action->ui['executor'] ?? UserAction::class);

$single_record_action->ui['executor'] = $executor;
$executor->addHook('afterExecute', function ($x) {
return $this->jsSave($this->notifyDefault);
});
} elseif ($single_record_action->short_name === 'delete') {
// if delete then we need this executor.
$executor = $this->owner->factory($single_record_action->ui['executor'] ?? jsUserAction::class);
$single_record_action->ui['executor'] = $executor;

$executor->addHook('afterExecute', function ($x) {
return (new jQuery())->closest('tr')->transition('fade left');
});
}

$executor = $this->factory($this->getActionExecutor($single_record_action));
$single_record_action->fields = ($executor instanceof jsUserAction) ? false : $this->editFields ?? true;
$single_record_action->ui['executor'] = $executor;
$executor->addHook('afterExecute', function ($x, $m, $id) {
return $m->loaded() ? $this->jsSave($this->notifyDefault) : $this->jsDelete();
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

$this->addAction($single_record_action);
}

// foreach ($m->getActions(Generic::NO_RECORDS) as $single_record_action) {
// $executor = $this->owner->add($single_record_action->ui['executor'] ?? UserAction::class);
// $executor->addHook('afterExecute', function ($x, $action_result) {
// if ($action_result === []) {
// // row was deleted
// } else {
// return $this->container->jsReload();
// }
// });
// $executor->setAction($single_record_action);
//
// $this->menu->addItem('add')->on('click', $single_record_action);
//
// //$single_record_action->ui['executor'] = [UserAction::class, 'jsSuccess'=>];
// //$this->addAction($single_record_action);
// }
foreach ($m->getActions(Generic::NO_RECORDS) as $single_record_action) {
$executor = $this->factory($this->getActionExecutor($single_record_action));
$single_record_action->fields = ($executor instanceof jsUserAction) ? false : $this->editFields ?? true;
$single_record_action->ui['executor'] = $executor;
$executor->addHook('afterExecute', function ($x, $m, $id) {
return $m->loaded() ? $this->jsSave($this->notifyDefault) : $this->jsDelete();
});
$btn = $this->menu->addItem(['Add new '.$this->model->getModelCaption(), 'icon' => 'plus']);
$btn->on('click.atk_CRUD', $single_record_action, [$this->name.'_sort' => $this->getSortBy()]);
}

return $this->model;
}

/**
* Return proper action executor base on model action.
*
* @param $action
*
* @throws \atk4\core\Exception
*
* @return object
*/
protected function getActionExecutor($action)
{
$executor = (!$action->args && !$action->fields && !$action->preview) ? $this->jsExecutor : $this->executor;

return $this->factory($executor);
}

/**
* Apply ordering to the current model as per the sort parameters.
*/
public function applySort()
{
parent::applySort();

if ($this->getSortBy() && $this->itemCreate) {
//Remove previous click handler to Add new Item button and attach new one using sort argument.
$this->container->js(true, $this->itemCreate->js()->off('click.atk_CRUD'));
$this->container->js(true,
$this->itemCreate->js()->on('click.atk_CRUD',
new jsFunction([
new jsModal('Add new', $this->pageCreate, [$this->name.'_sort' => $this->getSortBy()]),
]))
);
}
}

/**
Expand All @@ -120,14 +108,86 @@ public function applySort()
public function jsSave($notifier)
{
return [
// close modal
// new jsExpression('$(".atk-dialog-content").trigger("close")'),

// display notification
$this->factory($notifier, null, 'atk4\ui'),

// reload Grid Container.
$this->container->jsReload([$this->name.'_sort' => $this->getSortBy()]),
];
}

/**
* Return js statement necessary to remove a row in Grid when
* use in $(this) context.
*
* @return mixed
*/
public function jsDelete()
{
return (new jQuery())->closest('tr')->transition('fade left');
}

/**
* Set callback for edit action in CRUD.
* Callback function will receive the Edit Form and Executor as param.
*
* @param callable $fx
*
* @throws Exception
*/
public function onEditAction(callable $fx)
{
$this->setOnActionForm($fx, 'edit');
}

/**
* Set callback for add action in CRUD.
* Callback function will receive the Edit Form and Executor as param.
*
* @param callable $fx
*
* @throws Exception
*/
public function onAddAction(callable $fx)
{
$this->setOnActionForm($fx, 'add');
}

/**
* Set callback for both edit and add action form.
* Callback function will receive Forms and Executor as param.
*
* @param callable $fx
*
* @throws Exception
*/
public function onAction(callable $fx)
{
$this->onEditAction($fx);
$this->onAddAction($fx);
}

/**
* Set onAction callback using UserAction executor.
*
* @param callable $fx
* @param string $actionName
*
* @throws Exception
* @throws \atk4\core\Exception
* @throws \atk4\data\Exception
*/
public function setOnActionForm(callable $fx, string $actionName)
{
if (!$this->model) {
throw new Exception('Model need to be set prior to use on Form');
}

$ex = $this->model->getAction($actionName)->ui['executor'];
if ($ex && $ex instanceof UserAction) {
$ex->addHook('onStep', function ($ex, $step, $form) use ($fx) {
if ($step === 'fields') {
return call_user_func($fx, $form, $ex);
}
});
}
}
}
6 changes: 3 additions & 3 deletions src/View.php
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ public function on($event, $selector = null, $action = null, $defaults = null)
$actions[] = $cb;
} elseif ($action instanceof Generic) {
// Setup UserAction executor.
if ($action->ui['executor'] ?? null) {
if (isset($action->ui['executor'])) {
$class = $action->ui['executor'];
} elseif (isset($defaults['executor'])) {
$class = $defaults['executor'];
Expand All @@ -1172,10 +1172,10 @@ public function on($event, $selector = null, $action = null, $defaults = null)
if (isset($arguments[0])) {
$arguments[$ex->name] = $arguments[0];
}
if ($arguments['id'] ?? null) {
if (isset($arguments['id'])) {
$arguments[$ex->name] = $arguments['id'];
unset($arguments['id']);
} elseif ($arguments[0] ?? null) {
} elseif (isset($arguments[0])) {
// if id is not specify we assume arguments[0] is the model id.
$arguments[$ex->name] = $arguments[0];
unset($arguments[0]);
Expand Down
4 changes: 4 additions & 0 deletions src/jsToast.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

namespace atk4\ui;

use atk4\core\DIContainerTrait;

/**
* Class jsToast
* Generate a Fomantic-ui toast module command in js.
* $('body').toast({options}).
*/
class jsToast implements jsExpressionable
{
use DIContainerTrait;

/**
* Various setting options as per Fomantic ui toast module.
*
Expand Down