To simplify, I have companies and workers attached to them in my pyrocms app. In the companies (created by the table builder in the admin panel automatically), there are buttons in the raw of each company. edit
button is one of them provided out of the box. So I want to add another button, say 'Add Worker', and open the page of worker creation which I have done successfully. There is a multiple
relation between companies and workers since a worker can work in multiple companies. You can think it as a categories of any post. The thing I want is, in the worker creation form page, I want to have the company whose 'Add worker' button is clicked appear in the 'working companies' field of worker automatically. What is the proper way of implementing such idea? I can pass HTML attributes to button using attributes
but I don't know if it helps.
This is the $buttons array in the CompanyTableBuilder.
/**
* The table buttons.
* @var array|string
*/
protected $buttons = [
'edit',
'add_worker' => [
'attributes' => [
'href' => '/admin/crm/workers/create',
],
'text' => 'Add worker',
'type' => 'success',
]
];
Let's imagine you have two groups of clients: workers and payers
class ClientTableBuilder extends \Anomaly\UsersModule\User\Table\UserTableBuilder
{
/**
* The table model
*
* @var string
*/
protected $model = UserModel::class;
/**
* The table views.
*
* @var array
*/
protected $views = [
'workers' => [
'query' => WorkersQuery::class,
'buttons' => [
'jobs' => [
'type' => 'info',
],
],
],
'payers' => [
'query' => PayersQuery::class,
'buttons' => [
'payments' => [
'type' => 'info',
],
],
],
];
}
When you would press the jobs button, you will go to admin/{addon}/clients/jobs/{user_id}
route. So you would need to have the next one controller:
class ClientsController extends AdminController
{
/**
* Shows the clients list.
*
* @param ClientTableBuilder $table The table
* @return Response
*/
public function clients(ClientTableBuilder $table)
{
return $table->render();
}
/**
* Shows the client's jobs list.
*
* @param UserRepositoryInterface $users The users
* @param ClientJobsTableBuilder $table The table
* @param $id The identifier
* @return Response
*/
public function assignedJobs(
UserRepositoryInterface $users,
ClientJobsTableBuilder $table,
$id
) {
/* @var UserInterface $user */
if (!$user = $users->find($id)) {
return $this->response->json([
'success' => false,
'message' => "Can't find user with id {$id}!",
]);
}
if ($this->request->ajax()) {
$table->setAjax(true);
}
return $table->setUser($user)->render();
}
/**
* Shows modal with unassigned jobs list
*
* @param UserRepositoryInterface $users The users
* @param ClientJobsLookupTableBuilder $table The table
* @param $id The identifier
* @return Response
*/
public function unassignedJobs(
UserRepositoryInterface $users,
ClientJobsLookupTableBuilder $table,
$id
) {
/* @var UserInterface $user */
if (!$user = $users->find($id)) {
return $this->response->json([
'success' => false,
'message' => "Can't find user with id {$id}!",
]);
}
return $table->setUser($user)->render();
}
/**
* Attach a job to a client
*
* @param int|str $user The user's id
* @param int|str $job The job's id
* @return JsonResponse
*/
public function attach($user, $job)
{
if ($error = $this->dispatch(new AttachJobToUser($user, $job))) {
return $this->response->json([
'success' => false,
'message' => $error,
]);
}
return $this->response->json([
'success' => true,
'user' => (int) $user,
'job' => (int) $job,
]);
}
/**
* Detach a job from a client
*
* @param int|str $user The user's id
* @param int|str $job The job's id
* @return JsonResponse
*/
public function detach($user, $job)
{
if ($error = $this->dispatch(new DetachJobFromUser($user, $job))) {
return $this->response->json([
'success' => false,
'message' => $error,
]);
}
return $this->response->json([
'success' => true,
'user' => (int) $user,
'job' => (int) $job,
]);
}
}
Then a value TB looks like:
class ClientJobsTableBuilder extends ValueTableBuilder
{
/**
* Table's user
*
* @var UserInterface|null
*/
protected $user = null;
/**
* Table's columns
*
* @var array
*/
protected $columns = [
'name' => [
'heading' => 'Name',
'value' => '<strong>{entry.name}</strong>',
],
'type' => [
'heading' => 'Type',
],
'categories' => [
'heading' => 'Categories',
'value' => 'entry.type.categories.pluck("name")|join("<br>")',
],
];
/**
* Table's buttons
*
* @var string
*/
protected $buttons = ClientJobsTableButtons::class;
/**
* Table's actions
*
* @var array
*/
protected $actions = [];
/**
* Table's options
*
* @var array
*/
protected $options = [
'sortable' => true,
];
/**
* Table's assets
*
* @var array
*/
protected $assets = [
'scripts.js' => [
'{YOUR_MODULE_FULL_NS}::js/detach.js',
],
];
/**
* Gets the user.
*
* @return UserInterface|null The user.
*/
public function getUser()
{
return $this->user;
}
/**
* Sets the user.
*
* @param UserInterface $user The user
* @return self
*/
public function setUser(UserInterface $user)
{
$this->user = $user;
return $this;
}
}
then th valuetablebuttons:
class ClientJobsTableButtons
{
/**
* Handle the table buttons
*
* @param ClientJobsTableBuilder $builder The builder
*/
public function handle(ClientJobsTableBuilder $builder)
{
/* @var UserInterface $user */
if (!$user = $builder->getUser()) {
return;
}
$builder->setButtons([
'detach' => [
'type' => 'danger',
'data-detach' => '{entry.id}',
'data-user' => $user->getId(),
'data-dismiss' => 'multiple',
],
]);
}
}
And the same shit for the lookup TB:
class ClientJobsLookupTableBuilder extends TableBuilder
{
/**
* AJAX mode flag
*
* @var bool
*/
protected $ajax = true;
/**
* Table's user
*
* @var UserInterface|null
*/
protected $user = null;
/**
* Table's columns
*
* @var array
*/
protected $columns = [
'name' => [
'heading' => 'Name',
'value' => '<strong>{entry.name}</strong>',
],
'type' => [
'heading' => 'Type',
],
'categories' => [
'heading' => 'Categories',
'value' => 'entry.type.categories.pluck("name")|join("<br>")',
],
];
/**
* Table's buttons
*
* @var string
*/
protected $buttons = ClientJobsLookupTableButtons::class;
/**
* Table's actions
*
* @var array
*/
protected $actions = [];
/**
* Table's options
*
* @var array
*/
protected $options = [
'sortable' => false,
];
/**
* Table's assets
*
* @var array
*/
protected $assets = [
'scripts.js' => [
'{YOUR_MODULE_FULL_NS}::js/attach.js',
],
];
/**
* Gets the user.
*
* @return UserInterface|null The user.
*/
public function getUser()
{
return $this->user;
}
/**
* Sets the user.
*
* @param UserInterface $user The user
* @return self
*/
public function setUser(UserInterface $user)
{
$this->user = $user;
return $this;
}
}
And lookup TB buttons:
class ClientJobsLookupTableButtons
{
/**
* Handle the table buttons
*
* @param ClientJobsLookupTableBuilder $builder The builder
*/
public function handle(ClientJobsLookupTableBuilder $builder)
{
/* @var UserInterface $user */
if (!$user = $builder->getUser()) {
return;
}
$builder->setButtons([
'attach' => [
'data-attach' => '{entry.id}',
'data-user' => $user->getId(),
'data-dismiss' => 'multiple',
],
]);
}
}
After that you would need only to write some JS for right behavior.
UPD: This is the example of *Query class:
class WorkersQuery
{
/**
* Handle the query.
*
* @param Builder $query The query builder
* @param RoleRepositoryInterface $roles The roles repository
*/
public function handle(Builder $query, RoleRepositoryInterface $roles)
{
/* @var RoleInterface $role */
$role = $roles->findBySlug('worker');
$query
->leftJoin(
'users_users_roles',
'users_users_roles.entry_id',
'=',
'users_users.id'
)
->where('users_users_roles.related_id', $role->getId());
}
}
And the example of AttachJobToUser command:
class AttachJobToUser
{
/**
* User's identifier
*
* @var mixed
*/
protected $user;
/**
* Job's identifier
*
* @var mixed
*/
protected $job;
/**
* Create a new instance of AttachJobToUser class
*
* @param $user
* @param $job
*/
public function __construct($user, $job)
{
$this->user = $user;
$this->job = $job;
}
/**
* Handle the command
*
* @param UserRepositoryInterface $users The users
* @param JobRepositoryInterface $jobs The jobs
* @return boolean|string
*/
public function handle(
UserRepositoryInterface $users,
JobRepositoryInterface $jobs
) {
/* @var UserInterface $user */
if (!$user = $users->find($this->user)) {
return "Can't find user with id '{$this->user}'";
}
/* @var JobInterface $job */
if (!$job = $jobs->find($this->job)) {
return "Can't find job with id '{$this->job}'";
}
if (!$job->addWorker($user)) {
return "Can't attach a job with id '{$this->job}' to a worker with id '{$this->user}'";
}
return false;
}
}