A related list allow you to link some records to another one. For example, a customer can be linked to several invoices.
Uccello allows to displayed all related records using Related Lists.
You can use 2 types of related lists : n-1 and n-n.
Related List types
n-1
A Related List n-1 in a module, is linked to an entity field from another module. To be more explicit, let's take an example: we want to see all invoices related to a customer.
To be able to link an invoice to a customer you must create an entity field into the customer module.
// database/migrations/xxxx_xx_xx_xxxxxx_create_invoice_module.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Uccello\Core\Database\Migrations\Migration;
use Uccello\Core\Models\Field;
...
class CreateInvoiceModule extends Migration
{
public function up()
{
...
$this->createTable();
$this->createTabsBlocksFields($module);
}
protected function createTable()
{
Schema::create('invoices', function (Blueprint $table) {
...
$table->unsignedInteger('customer_id')->nullable();
...
});
}
protected function createTabsBlocksFields($module)
{
...
// Field customer
$field = Field::create([
'module_id' => $module->id,
'block_id' => $block->id,
'name' => 'customer',
'uitype_id' => uitype('entity')->id,
'displaytype_id' => displaytype('everywhere')->id,
'sequence' => $block->fields()->count(),
'data' => [ "rules" => "required", "module" => "customer" ] // Linked to the customer module
]);
}
...
}
We will create a Related List n-1 and link it to the field freshly created.
// database/migrations/xxxx_xx_xx_xxxxxx_create_customer_module.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Uccello\Core\Database\Migrations\Migration;
use Uccello\Core\Models\Module;
use Uccello\Core\Models\Field;
use Uccello\Core\Models\Relatedlist;
...
class CreateCustomerModule extends Migration
{
public function up()
{
...
$this->createRelatedLists($module);
}
protected function createRelatedLists($module)
{
$relatedModule = Module::where('name', 'invoice')->first();
Relatedlist::create([
'module_id' => $module->id,
'related_module_id' => $relatedModule->id,
'related_field_id' => $relatedModule->fields->where('name', 'customer')->first()->id, // Retrieve the field created before
'tab_id' => null,
'label' => 'relatedlist.invoices', // Will be translated
'type' => 'n-1',
'method' => 'getDependentList',
'sequence' => $module->relatedlists()->count(),
'data' => [ 'actions' => [ 'add' ] ]
]);
}
...
}
Now, if you visit a customer record, a new tab will display all the invoices related to it. You can create new ones and they will be directly linked to the customer.
n-n
A Related List n-n allows to link a same record to others records from different modules. To be more explicit, let's take an example: we want to link several documents to several customers.
To be able to do this we need to create an association table:
// database/migrations/xxxx_xx_xx_xxxxxx_create_rl_customers_documents_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRlCustomersDocumentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('rl_customers_documents', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('customer_id');
$table->unsignedInteger('document_id');
$table->timestamps();
// Foreign keys
$table->foreign('customer_id')
->references('id')->on('customers')
->onDelete('cascade');
$table->foreign('document_id')
->references('id')->on('documents')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('rl_customers_documents');
}
}
We will create a Related List n-n:
// database/migrations/xxxx_xx_xx_xxxxxx_create_customer_module.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Uccello\Core\Database\Migrations\Migration;
use Uccello\Core\Models\Module;
use Uccello\Core\Models\Field;
use Uccello\Core\Models\Relatedlist;
...
class CreateCustomerModule extends Migration
{
public function up()
{
...
$this->createRelatedLists($module);
}
protected function createRelatedLists($module)
{
...
$documentModule = Module::where('name', 'document')->first();
Relatedlist::create([
'module_id' => $module->id,
'related_module_id' => $documentModule->id,
'tab_id' => null,
'label' => 'relatedlist.documents', // Will be translated
'type' => 'n-n',
'method' => 'getRelatedList',
'sequence' => $module->relatedlists()->count(),
'data' => [ 'actions' => [ 'add', 'select' ] ]
]);
}
...
}
// app/Customer.php
<?php
namespace App;
use Uccello\Core\Database\Eloquent\Model;
...
class Customer extends Model
{
public function documents()
{
return $this->belongsToMany(Document::class, 'rl_customers_documents')->withTimestamps();
}
}
// app/Document.php
<?php
namespace App;
use Uccello\Core\Database\Eloquent\Model;
...
class Document extends Model
{
public function customers()
{
return $this->belongsToMany(Customer::class, 'rl_customers_documents')->withTimestamps();
}
}
Now, if you visit a customer record, a new tab will display all the document related to it. You can select existant documents to link to the record or create new ones.
Options
Display in a Tab or a Block?
By default, a Related List is displayed in a Tab. If you prefer, you can display it in an existant tab. The Related List will be displayed like a new block at the bottom of the page.
To do this, simply fill in tab_id with a valid tab's id from the current module.
protected function createRelatedLists($module)
{
$documentModule = Module::where('name', 'document')->first();
Relatedlist::create([
'module_id' => $module->id,
'related_module_id' => $documentModule->id,
'tab_id' => $module->tabs->first()->id, // The Related List will be displayed as a new block in the first tab
'label' => 'relatedlist.documents', // Will be translated
'type' => 'n-n',
'method' => 'getRelatedList',
'sequence' => $module->relatedlists()->count(),
'data' => [ 'actions' => [ 'add', 'select' ] ]
]);
}
Properties
Attribute
Type
Description
Default
module_id
int
Id of the source module in with display the related list.
related_module_id
int
Id of the target module to which the related list points.
related_field_id
int
null
tab_id
int
Id of the tab in which display the related list. If it is null, Uccello displays the related list in a new tab of the Detail View.
null
label
string
Related list's name. It can be translated if you add the translation in the module localization file.
type
string
Type of the related list.
n-1 or n-n.
method
string
Method to use for retrieving the related records.
By default, set getDependentList for a n-1 related list and getRelatedList for a n-n one.
To use your own method please refer to the example below.
sequence
int
The display sequence for ordering related lists.
data
array
Useful to pass some settings params.
By default you can use the following structure:
[
'actions' => [
'add',
'select'
]
]
This parameter allows to configure the buttons you want to display in the related list.
select: The user can select a record if he has the retrieve capability on the related module.
add: The user can create a new related record if he has the create capability on the related module.
You can adapt the contains of actions to use 0, 1 or 2 buttons (e.g. [ 'actions' => [ 'add'] ]).
If you don't want to display action buttons, simply let actions empty.
null
You can create your own method for retrieving the related records. To do this you have to create 2 functions in the model in which add the related list.
myOwnMethod: You can use the name of you want
myOwnMethodCount: The same name as the method above, suffixed by Count
Example
<?php
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Uccello\Core\Models\Relatedlist;
use Uccello\Core\Support\Traits\UccelloModule;
class Person extends Model
{
use UccelloModule;
...
/**
* Retrieves related records for n-n relations
*
* @param Relatedlist $relatedList
* @param integer $recordId
* @param Builder|null $query
* @param int $start
* @return Collection
*/
public function myOwnMethod(Relatedlist $relatedList, int $recordId, ?Builder $query = null)
{
$modelClass = $relatedList->module->model_class;
$relationName = $relatedList->relationName;
$record = $modelClass::find($recordId);
$filter = ['order' => request('order')];
$query = $record->$relationName()
->filterBy($filter);
return $query;
}
/**
* Counts related records for n-n relations
*
* @param Relatedlist $relatedList
* @param integer $recordId
* @return int
*/
public function myOwnMethodCount(Relatedlist $relatedList, int $recordId) : int
{
return $this->myOwnMethod($relatedList, $recordId)->count();
}
}