This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.

oskar.villani40843
oskar.villani40843

Hi,

I'd like to inject some relations - belongsTo and belongsToMany into the User plugin. E.g. linking a person to a company he is working with (stored in another table) or the make of car stored in another list too.

I know already how to add fields - either directly or from an extra table - thanks to some tutorial videos from Samuel Georges an Watch&Learn but unfortunately the belongsToMany is covered not completely and belongsTo is almost not mentioned. At least I could find not all pieces of the puzzle :/

So, any hints and tricks? 0:)

Thanks in advance!

Last updated

mjauvin
mjauvin

I don't understand what you're looking for... this?

User::extend(function ($model) {
    $model->belongsTo[
        'company' => Company::class, 
   ];
});
oskar.villani40843
oskar.villani40843

Hello (again) mjauvin,

yes from the point of intention. I'd like to xtend the user.plugin of course without editing the user plugins code directly - update-save. Let's name the plugin myPlugin and the model company where I want to start.

Step 1: For the plugin.php of myPluginModel I've got - a little different to your code, but same result as I guess:

pubic function boot{
    \Rainlab\User\Models\User::extend(function($model) {
        $model->belongsTo['company'] => 'Pds\myPlugin\Models\Company'
    }
    ...
)};

Step 2: I also injected a field named pds_company_id into the User plugin as Samuel Georges describes in his video - second appraoch, inserting the field directly into the table. Because a belongsTo requires a field where the key id of the related table is stored, as I found in the docs. The initial 'pds_' is for the sake of order and not to collide with may be other plugins.

Step 3: I added some other fields to the User plugin (as also described by S. Georges) onto the plugin.php of myPluginModel

Anyhow there are two questions left

  • the user model has no relation behaviour, and I could find no working way how to add this
  • I could not find a working code how to inject a relation field - at least anywhere - for a belongsTo relation into the user plugins model view (backend so far)

Well, I am stuck in this for some days, getting more puzzled than before unfortunately, beard growing ;)=====

Thanks in advance Oskar

mjauvin
mjauvin

ok, you need to implement the relation controller behavior to the users controller as well like so:


UsersController::extend(function($users) {
   if (!isset($users->relationConfig)) {
      $users->addDynamicProperty('relationConfig');
   }                                                
   $myConfigPath = '$/author/plugin/config/user_relations.yaml';
   $users->relationConfig = $users->mergeConfig($users->relationConfig, $myConfigPath);              
   if (!$users->isClassExtendedWith('Backend.Behaviors.RelationController')) { 
      $users->extendClassWith(\Backend\Behaviors\RelationController::class);                         
   }
});
oskar.villani40843
oskar.villani40843

Hello mjauvin,

thanks a lot for your tips, they helped me out in this and finally I got it running.

Here is the final code I'd like to share (and as a reminder to me ;)

Objective was to inject a relation into the Rainlab.User plugin to enrich the plugin with a field ( a dropdown in this case) to select from a list of companies. Therefore a belongsTo relation is required. This list of companies is stored in another table of the plugin to be made - or of course added to an existing one. Lets sum it up step by step:

Step 1: Create a plugin (I did so with builder). Namespace for this example is Pds\Pdsuserprofile

Step 2: Create the table to be referenced to. In this example the table is called pds_companies. It has a field named/for id as usual and a field called name for the name of the company (any other can be added as required too).

Step 3: Create a model and controller as well (either by builder or by command line) for the table in step 2. Model is called PdsCompany and controller is called PdsCompanies here. Create a columns.yaml and a fields.yaml (e.g. with builder) too.

Step 4: An Plugin update has to be created to add fields to the user plugin. In this case I decided to add these fields directly. That is possible and, as far as I see, works without any complications with other user-plugin related plugins (like the blog plugin). A detailed tutorial is here: https://www.youtube.com/watch?v=0ujNMvOmrOg the part with fields directly added to the user table starts at approx 10:00

For this add a file add_pdsuserprofile_fields.php to the folder pds/pdsuserprofile/updates/ Code is:

<?php namespace Pds\Pdsuserprofile\Updates;

use Schema;
use October\Rain\Database\Updates\Migration;

class AddPdsUserprofileFields extends Migration
{
    // this function adds fields to the user database
    public function up()
    {
        // exit if fields are already existing
        if (Schema::hasColumns('users', ['pds_nickname', 'pds_company_id'])) {
            return;
        }

        // here the fields to be added are defined 
        // I decided to use a prefix for each field for non-colliding to maybe other
        // plugins adding fields
        Schema::table('users', function ($table) {

            // just an example how to directly save data
            $table->string('pds_nickname', 24)->nullable(); 

            // the relation index: a field storing the id of 
            // the related company in the pds_companies table
            $table->integer('pds_company_id')->nullable();       

        });
    }

    // this function deletes the fields in case the plugin is removed
    public function down()
    {
        // old (don't use)
        //$table->dropDown([
        //    pds_nickname,
        //    pds_company_id
        //]);

        // correct version
        Schema::table('users', function ($table) {
          $table->dropColumn(['pds_nickname', 'pds_company_id']);
       });

    }
}

In addition the /pds/pdsuserprofile/updates/version.yaml must be completed with some lines to make the changes work. If the existing version ist e.g. like this:

1.0.1:
    - First version of pdsuserprofile
    - initialize plugin

It has to be completed to:

1.0.1:
    - First version of pdsuserprofile
    - initialize plugin
1.0.2:
    - Adding some new fields 
    - add_pdsuserprofile_fields.php 

Now the plugin has to be refreshed to add the new fields to the table. This can be done bei either the console with "php artisan plugin:refresh Pds.Pdsuserprofile" or - if you don't have access to the console with the Web Artisan plugin by Vojta Svoboda. With the last one installed, there is an url to call in the browser like www.mydomain.com/artisan/v1/plugin/refresh/pds/pdsuserprofile/{somesecuritycode} and you are fine (hope so).

Step 5: Create a yaml file to define required information about the belongsTo relation as described in the docs (https://octobercms.com/docs/backend/relations#belongs-to). I created this file named as user_relations.yaml in a /config/ subdirectory of my plugin: /pds/pdsuserprofile/config/user_relations.yaml Code is

# ===================================================
#  Relation Behavior Config for User plugin injection
# ===================================================
pds_company:
    label: Company
    view:
        list: $/pds/pdsuserprofile/models/pdscompany/columns.yaml
        toolbarButtons: add|remove
        showSorting: true
    manage:
        form: $/pds/pdsuserprofile/models/pdscompany/fields.yaml
        showCheckboxes: true
        showSearch: true

Step 6: Next is to 'inject' the required information into the rainlab.user plugin. Not directly into the plugin code , this would not be update-save, the coding is done in the Plugin.php of the own Pdsuserprofile plugin at /pds/pdsuserprofile/Plugin.php. The following lines of code are an excerpt of the lines required. Lines with "..." are indicating code not required for this example:

<?php namespace Pds\Pdsuserprofile

use Backend;
use System\Classes\PluginBase;
use Rainlab\User\Models\User as UserModel;
use Rainlab\User\Controllers\Users as UsersController;

...

class Plugin extends PluginBase

{
    ...

    // make  sure the rainlab.user plugin is loaded already
    // otherwise this won't work
    public $require = ['RainLab.User'];

    // add this boot function which is called at startup
    public function boot()
    {

        UsersController::extend(function($users) {
            if (!isset($users->relationConfig)) {
                $users->addDynamicProperty('relationConfig');
            }

            // let oc know where the relation is defined
            $myConfigPath = '$/pds/pdsuserprofile/config/user_relations.yaml';

            $users->relationConfig = $users->mergeConfig($users->relationConfig, $myConfigPath);

            if (!$users->isClassExtendedWith('Backend.Behaviors.RelationController')) {
                $users->extendClassWith(\Backend\Behaviors\RelationController::class);
            }
        });

        // now the type of relation is provided to Rainlab.user
        UserModel::extend(function($model) {
            $model->belongsTo['pds_company'] = [
                    'Pds\Pdsuserprofile\Models\PdsCompany', 
                    'key' => 'pds_company_id'];

        });

        // lastly we have to inject a field into the rainlab.user form to display
        UsersController::extendFormFields(function($form, $model, $context){

           // do this only if the rainlab.user is active
            if(!$model instanceof UserModel)
                return;

            // and her are two fields to display
            // 1. the relation field to the companies
            // 2. another field as an example to store some infos
            $form->addTabFields([

                'pds_nickname' => [
                    'label' => 'Nickname',
                    'commentAbove' => 'Is shown on the dashboard.',
                    'span' => 'left',
                    'type' => 'text',
                    'required' => true,
                    'tab' => 'Contact'
                ],
                'pds_company' => [
                    'label' => 'Company',
                    'commentAbove' => 'Employee of:',
                    'span' => 'right',
                    'type' => 'relation',
                    'required' => false,
                    'tab' => 'Contact'
                ]
            ]);
        });

        ...

    }
}

Now the to new fields should be visible in the Rainlab User form within a tab named "Contact"

Last updated

mjauvin
mjauvin

Please note that the down() method in your migration file should be as below:

public function down()
{
    Schema::table('users', function ($table) {
        $table->dropColumn(['pds_nickname', 'pds_company_id']);
    });
}
oskar.villani40843
oskar.villani40843

Hi mjauvin,

thanks for the revision! I re-edited the code above, just in case someone does not scroll down completely ;)

{ mjauvin said:

Please note that the down() method in your migration file should be as below:

public function down()
   Schema::table('users', function ($table) {
       $table->dropColumn(['pds_nickname', 'pds_company_id']);
   });
}

Last updated

1-7 of 7

You cannot edit posts or make replies: the forum has moved to talk.octobercms.com.