XF 2.1 Should I use custom user field or define my own table

abdfahim

Well-known member
I need to associate 30 additional information with each user which would be accessible from everywhere such as member's page, member's tooltip, below member's avatar in a thread_view - basically what custom user fields are meant to be.

But I also want all those values for all the members to be listed in a standalone portal page - i.e. I need a single query to extract all the data for all the users which is a bit tricky with xf_user_field_value table because of its unique structure (I have the query, but it's a bit complex).

Instead, if I define a new table with 30+1 columns (extra column for user_id), it would be a very easy and straightforward query to fetch all data for all users in the portal page. However, I am not sure how would I make them available everywhere like in the thread_view, members etc. I think somehow I have to modify the entity/structure somewhere.

Can the experts comment on my situation, please? Should I use the custom user field at the expanse of a complex query in the portal page, or define a new table at the expanse of somehow attaching that information to the user data. If the latter is better, how would I do that?

Thanks
 
Last edited:

Lukas W.

Formerly katsulynx
Firstly, don't use direct queries, use an entity.

A simple entity for your database table could look like the following. The file should go into src/addons/My/Addon/Entity/MyEntity.php
Code:
<?php

namespace My\AddOn\Entity;

use XF\Mvc\Entity\Entity;
use XF\Mvc\Entity\Structure;

class MyEntity extends Entity {
    public static function getStructure(Structure $structure) {
        $structure->table = 'xf_my_entity_table';
        $structure->shortName = 'My\AddOn:MyEntity';
        $structure->primaryKey = 'user_id';
        $structure->columns = [
            'user_id' => ['type' => self::UINT, 'unique' => true, 'primary' => true],
            // Definition of your other 30 columns,
            // check existing entites in src/XF/Entity
            // on how to define them
        ];

        return $structure;
    }
}
Once you have that, you can generate the setup query with php cmd.php xf-dev:generate-schema-entity My\AddOn:MyEntity in the cli to paste it over to your setup.php.

When you have your entity, you can set up a relation to the XF user entity to make it available everywhere where the XF user entity is available.

Create the following file in src/addons/My/AddOn/Listener/EntityStructure.php:
Code:
<?php

namespace My\AddOn\Listener;

use XF\Mvc\Entity\Entity;
use XF\Mvc\Entity\Manager;
use XF\Mvc\Entity\Structure;

class EntityStructure
{
    public static function xfUser(Manager $em, Structure &$structure)
    {
        $structure->relations['MyEntityData'] = [
            'entity' => 'My\AddOn:MyEntity',
            'type' => Entity::TO_ONE,
            'conditions' => 'user_id',
            'primary' => true
        ];

        $structure->defaultWith[] = 'MyEntityData';
    }
}

To do that, create an event listener (ACP > Development > Execution manipulation > Code event listeners). It is supposed to listen to the entity_structure event with the event hint XF:User and the execute callback My\AddOn\Listener\EntityStructure :: xfUser. That will make your data accessible everywhere where you have a user entity (e.g. in a template with a {$user} object via {$user.MyEntityData.one_of_the_columns}).
 

nocte

Well-known member
You could also consider extending XF:User (table xf_user) with 1 blob column and save all your data in the JSON format in this column. 🤔
 

abdfahim

Well-known member
@Lukas W. .. works like a charm! Thanks a lot! Just one question though, what is the use of doing this
Once you have that, you can generate the setup query with php cmd.php xf-dev:generate-schema-entity My\AddOn:MyEntity in the cli to paste it over to your setup.php.
 

nocte

Well-known member
Just one question though, what is the use of doing this
This should create a code for your Setup.php which you can use to create the tables - so you don't have to write all Setup.php code by yourself (did not know about that, but seems to be very handy :))

Anyway, there seems to be a problem with slashes/backslashes on my system - I always get:
Code:
Entity class for VendorAddon:Entity (VendorAddon\Entity\Entity) could not be created.
when i enter:
Code:
php cmd.php xf-dev:generate-schema-entity Vendor\Addon:Entity
But for the entity XFMG:Album (which does not include a slash) is works.

Edit: O.k. for me this works (2 backslashes):
Code:
php cmd.php xf-dev:generate-schema-entity Vendor\\Addon:Entity
 
Last edited:

pm4

Member
Hi,
I have tried this same example, but it seems to not work.
I'm using Xenforo 2.0

PHP:
<?php
namespace DM\BuyersPage\Entity;

use XF\Mvc\Entity\Structure;

class Buyer extends \XF\Mvc\Entity\Entity
{
    public static function getStructure(Structure $structure)
    {
        $structure->table = 'dm_buyers';
        $structure->shortName = 'DM\BuyersPage:Buyer';
        $structure->primaryKey = 'user_id';
        $structure->columns = [
            'user_id' => ['type' => self::UINT, 'unique' => true, 'primary' => true],
            'name' => ['type' => self::STR, 'required' => true],
            'surname' => ['type' => self::STR, 'required' => true],
            'email' => ['type' => self::STR, 'required' => true],
            'paypal_address' => ['type' => self::STR],
            'created_on' => ['type' => self::INT, 'default' => time()],
            'active' => ['type' => self::BOOL]
        ];
        $structure->getters = [];
        $structure->relations = [

        ];
        return $structure;
    }
}
?>
PHP:
<?php

namespace DM\BuyersPage\Listener;

use XF\Mvc\Entity\Entity;
use XF\Mvc\Entity\Manager;
use XF\Mvc\Entity\Structure;

class EntityStructure
{
    public static function xfUser(\XF\Mvc\Entity\Manager $em, \XF\Mvc\Entity\Structure &$structure)
    {
        $structure->relations['BuyerData'] = [
            'entity' => 'DM\BuyersPage:Buyer',
            'type' => Entity::TO_ONE,
            'conditions' => 'user_id',
            'primary' => true
        ];

        $structure->defaultWith[] = 'BuyerData';
    }
}
?>
Screenshot from 2019-03-16 06-29-48.png

Can someone help?
Thank you.
 
Top