Skip to content

Commit e6f8c99

Browse files
committed
WIP add atk4/mastercrud c893b74
1 parent 92b4a44 commit e6f8c99

File tree

6 files changed

+1384
-0
lines changed

6 files changed

+1384
-0
lines changed

mastercrud-develop/README.md

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
[ATK UI](https://github.com/atk4/ui) is a UI library for building UI interfaces that has a built-in [CRUD](http://ui.agiletoolkit.org/demos/crud.php) component. It can be used to create complex admin systems, but it requires you to populate multiple pages and inter-link them together yourself.
2+
3+
![mastercrud](docs/images/mastercrud.png)
4+
5+
**MasterCRUD** is an add-on for ATK UI and ATK Data, which will orchestrate navigation between multiple CRUD pages by respecting relations and conditions. You can use **MasterCRUD** to:
6+
7+
- Manage list of clients, and their individual invoices and payments.
8+
- Manage user groups and users within them
9+
- Manage multi-level catalogue and products in them
10+
11+
The syntax of **MasterCRUD** is incredibly simple and short. It automatically takes care of many details like:
12+
13+
- record and track `id` of various records you have clicked on (BreadCrumb)
14+
- display multi-Tab pages with model details and optional relations
15+
- support `hasOne` and `hasMany` relations
16+
- allow flexible linking to a higher tree level (user - invoice - allocated_payment -> payment (drops invoice_id))
17+
18+
**MasterCRUD** can also be extended to contain your own views, you can interact with the menu and even place **MasterCRUD** inside a more complex layouts.
19+
20+
### Example Use Case (see demos/clients.php for full demo):
21+
22+
Assuming you have Clients with Invoices and Payments and you also want to add "Line"s for each Invoice, you may want to add this interface for the admin, where user can use drill-downs to navigate through data:
23+
24+
![step1](docs/images/step1.png)
25+
26+
Clicking on `Client 2` would bring you to a different page. Extra tabs Invoices and Payments offer you further way in:
27+
28+
![step2](docs/images/step2.png)
29+
30+
clicking on specific invoice, you can edit it's lines:
31+
32+
![step3](docs/images/step3.png)
33+
34+
On this screen however we turned off deletion of lines (because it is a demo). However clicking Edit brings up a Modal where you can easily update record data:
35+
36+
![step4](docs/images/step4.png)
37+
38+
39+
40+
All this UI can be created in just a few lines of code!
41+
42+
43+
44+
MasterCRUD operates like a regular CRUD, and you can easily substitute it in:
45+
46+
``` php
47+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
48+
$crud->setModel('Client');
49+
```
50+
51+
You'll noticed that you can now click on the client name to get full details about this client. Next, we want to be able to see and manage Client invoices:
52+
53+
``` php
54+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
55+
$crud->setModel('Client', ['Invoices'=>[]]);
56+
```
57+
58+
This will add 2nd tab to the "Client Details" screen listing invoices of said client. If you invoice is further broken down into "Lines", you can go one level deeper:
59+
60+
``` php
61+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
62+
$crud->setModel('Client', ['Invoices'=>['Lines'=>[]]]);
63+
```
64+
65+
If `Client hasMany('Payments')` then you can also add that relation:
66+
67+
``` php
68+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
69+
$crud->setModel('Client', ['Invoices'=>['Lines'=>[]], 'Payments'=>[]]);
70+
```
71+
72+
With some cleanup, this syntax is readable and nice:
73+
74+
``` php
75+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
76+
$crud->setModel('Client', [
77+
'Invoices'=>[
78+
'Lines'=>[]
79+
],
80+
'Payments'=>[]
81+
]);
82+
```
83+
84+
## Support for actions
85+
86+
MasterCRUD is awesome for quickly creating admin systems. But basic C,R,U,D operations are not enough. Sometimes you want to invoke custom actions for individual element. MasterCRUD now supports that too:
87+
88+
```php
89+
$app->layout->add(new \atk4\mastercrud\MasterCRUD())
90+
->setModel(new \saasty\Model\App($app->db),
91+
[
92+
'columnActions'=>[
93+
'repair'=>['icon'=>'wrench'],
94+
],
95+
'Models'=>[
96+
'columnActions'=>[
97+
'migrate'=>['icon'=>'database'],
98+
],
99+
'Fields'=>[
100+
'ValidationRules'=>[],
101+
102+
],
103+
'Relations'=>[
104+
'ImportedFields'=>[],
105+
],
106+
],
107+
```
108+
109+
![actions](docs/images/actions.png)
110+
111+
There are various invocation methods allowing you to specify icon, label, custom callbacks etc.
112+
113+
This also adds "MethodInvocator" - a view which asks you for arguments and then executes them.
114+
115+
This next example will use form to ask for an email, which will then be passed as argument to sendEmail($email)
116+
117+
```php
118+
[
119+
'columnActions'=>[
120+
'sendEmail' => ['icon'=>'wrench', 'email'=>'string']
121+
]
122+
]
123+
```
124+
125+
126+
127+
128+
129+
### Installation
130+
131+
Install through composer:
132+
133+
``` bash
134+
composer require atk4/mastercrud
135+
```
136+
137+
Also see introduction for [ATK UI](https://github.com/atk4/ui) on how to render HTML.
138+
139+
## Roadmap
140+
141+
- [x] Allow to specify custom CRUD seed. You can ever replace it with your own compatible view.
142+
- [x] Add custom actions and function invocation
143+
- [ ] Create decent "View" mode (relies on ATK UI Card)
144+
- [ ] Traverse hasOne references (see below)
145+
146+
147+
148+
149+
150+
151+
152+
153+
154+
155+
156+
157+
158+
159+
160+
-------------------------
161+
162+
> NOT IMPLEMENTED BELOW
163+
164+
Suppose that `Invoice hasMany(Allocation)`and `Payment hasMany(Allocation)` while allocation can have one Payment and one Invoice.
165+
166+
``` php
167+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
168+
$crud->setModel('Client', [
169+
'Invoices'=>[
170+
'Lines'=>[],
171+
'Allocations'=>[]
172+
],
173+
'Payments'=>[
174+
'Allocations'=>[]
175+
]
176+
]);
177+
```
178+
179+
That's cool, but if you go through the route of `Invoice -> allocation ->` you should be able to click on the "payment":
180+
181+
``` php
182+
$crud = $app->add('\atk4\mastercrud\MasterCRUD');
183+
$crud->setModel('Client', [
184+
'Invoices'=>[
185+
'Lines'=>[],
186+
'Allocations'=>[
187+
'payment_id'=>['path'=>'Payments', 'payment_id'=>'payment_id']
188+
]
189+
],
190+
'Payments'=>[
191+
'Allocations'=>[
192+
'invoice_id'=>['path'=>'Invoices', 'invoice_id'=>'invoice_id']
193+
]
194+
]
195+
]);
196+
```
197+
198+
Now you will be able to jump from `Invoice->allocation` to `Payment` and other way around.
199+
200+

mastercrud-develop/demos/basic.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Atk4\MasterCrud\Demo;
6+
7+
include 'init.php';
8+
9+
use Atk4\MasterCrud\MasterCRUD;
10+
use Atk4\Ui\Crud;
11+
12+
$app->cdn['atk'] = '../public';
13+
$mc = $app->add([
14+
MasterCRUD::class,
15+
'ipp' => 5,
16+
'quickSearch' => ['name'],
17+
]);
18+
$mc->setModel(
19+
new Client($app->db),
20+
[
21+
'Invoices' => [
22+
'Lines' => [
23+
['_crud' => [Crud::class, 'displayFields' => ['item', 'total']]],
24+
],
25+
'Allocations' => [],
26+
],
27+
'Payments' => [
28+
'Allocations' => [],
29+
],
30+
]
31+
);

mastercrud-develop/demos/init.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Atk4\MasterCrud\Demo;
6+
7+
require '../vendor/autoload.php';
8+
9+
require 'db.php';
10+
11+
use Atk4\Data\Model;
12+
use Atk4\Data\Persistence;
13+
use Atk4\Ui\App;
14+
use Atk4\Ui\Layout;
15+
use Atk4\Ui\Message;
16+
17+
$app = new App('MasterCRUD Demo');
18+
$app->initLayout([Layout\Centered::class]);
19+
20+
// change this as needed
21+
try {
22+
$app->db = new Persistence\Sql('pgsql://root:root@localhost/root');
23+
} catch (\Exception $e) {
24+
$app->add([Message::class, 'Database is not available', 'error'])->text
25+
->addParagraph('Import file demos/mastercrud.pgsql and see demos/db.php')
26+
->addParagraph($e->getMessage());
27+
28+
exit;
29+
}
30+
31+
class Client extends Model
32+
{
33+
public $table = 'client';
34+
35+
protected function init(): void
36+
{
37+
parent::init();
38+
39+
$this->addField('name', ['required' => true]);
40+
$this->addField('address', ['type' => 'text']);
41+
42+
$this->hasMany('Invoices', ['model' => new Invoice()]);
43+
$this->hasMany('Payments', ['model' => new Payment()]);
44+
}
45+
}
46+
47+
class Invoice extends Model
48+
{
49+
public $table = 'invoice';
50+
public $title_field = 'ref_no';
51+
52+
protected function init(): void
53+
{
54+
parent::init();
55+
56+
$this->hasOne('client_id', ['model' => new Client()]);
57+
58+
$this->addField('ref_no');
59+
$this->addField('status', ['enum' => ['draft', 'paid', 'partial']]);
60+
61+
$this->hasMany('Lines', ['model' => new Line()])
62+
->addField('total', ['aggregate' => 'sum']);
63+
64+
$this->hasMany('Allocations', ['model' => new Allocation()]);
65+
}
66+
}
67+
68+
class Line extends Model
69+
{
70+
public $table = 'line';
71+
public $title_field = 'item';
72+
73+
protected function init()
74+
{
75+
parent::init();
76+
77+
$this->hasOne('invoice_id', ['model' => new Invoice()]);
78+
$this->addField('item');
79+
$this->addField('qty', ['type' => 'integer']);
80+
$this->addField('price', ['type' => 'money']);
81+
82+
$this->addExpression('total', '[qty]*[price]');
83+
}
84+
}
85+
86+
class Payment extends Model
87+
{
88+
public $table = 'payment';
89+
public $title_field = 'ref_no';
90+
91+
protected function init()
92+
{
93+
parent::init();
94+
95+
$this->hasOne('client_id', ['model' => new Client()]);
96+
97+
$this->addField('ref_no');
98+
$this->addField('status', ['enum' => ['draft', 'allocated', 'partial']]);
99+
$this->addField('amount', ['type' => 'money']);
100+
101+
$this->hasMany('Allocations', ['model' => new Allocation()]);
102+
}
103+
}
104+
105+
class Allocation extends Model
106+
{
107+
public $table = 'allocation';
108+
public $title_field = 'title';
109+
110+
protected function init()
111+
{
112+
parent::init();
113+
114+
$this->addExpression('title', '\'Alloc \' || [id]');
115+
116+
$this->hasOne('payment_id', ['model' => new Payment()]);
117+
$this->hasOne('invoice_id', ['model' => new Invoice()]);
118+
$this->addField('allocated', ['type' => 'money']);
119+
}
120+
}

0 commit comments

Comments
 (0)