XF 2.1 Add data in newly created table in Addon's Setup.php file

asprin

Active member
So the addon that I'm building has this in the Setup file

PHP:
public function installStep1()
{
    $this->schemaManager()->createTable('xf_asp_fb_sport', function(Create $table)
    {
        $table->addColumn('sys_id', 'int')->autoIncrement();
        $table->addColumn('title', 'varchar', 20);
        $table->addPrimaryKey('sys_id');
    });
  
    // table has been created, dump some sample data into it
    $db = $this->db();
    $db->insert('xf_asp_fb_sport', [
        'title'  => 'Football'
    ]);
}

(a) Is this the correct way of inserting initial data in a table inside a Setup file?
(b) Is there a way I can insert multiple rows at once instead of using "$db->insert()" statement for each row?
 
Solution
You can use insertBulk on the DB object to pass multiple rows at once as the second argument. Keep in mind that this won't fire any entity events like postSave in case you need them, you'll either have to perform steps there manually or sequentially create the entities in your installer.

Either way, setting up default data in your installer is not something to refrain from and reasonable to do.

VersoBit

Well-known member
I would highly recommend using @Xon's Standard Library as there are some nice things that can make the installer process a bit nicer (for coding anyways). https://github.com/Xon/XenForo2-StandardLib < see here for the dev documentation.

From what I've read above, It would appear you are using the correct markup.
(a) Is this the correct way of inserting initial data in a table inside a Setup file?
I personally would not fill initial data beyond structure with an addon.
(b) Is there a way I can insert multiple rows at once instead of using "$db->insert()" statement for each row?
Pretty sure you could turn that into an array, though I could be wrong:
PHP:
$db->insert('xf_asp_fb_sport',
            {
                [
                    'title'  => 'Football'
                ],
                [
                    'title'  => 'Baseball'
                ],
                [
                    'title'  => 'eSports'
                ]
            }
);
 

Lukas W.

Well-known member
You can use insertBulk on the DB object to pass multiple rows at once as the second argument. Keep in mind that this won't fire any entity events like postSave in case you need them, you'll either have to perform steps there manually or sequentially create the entities in your installer.

Either way, setting up default data in your installer is not something to refrain from and reasonable to do.
 
Solution

VersoBit

Well-known member
How would you go about populating a table with some necessary data (one with which you cannot have the addon working) then?
I would consider that structure and add it to the setup file.

If you're using Xon's tool, you can do something like this with your installer, which is much cleaner to work with - Below is an example of creating a table, and then modifying two tables for additional data:
PHP:
<?php

namespace Namespace\AppName;

use XF\AddOn\AbstractSetup;
use XF\AddOn\StepRunnerInstallTrait;
use XF\AddOn\StepRunnerUninstallTrait;
use XF\AddOn\StepRunnerUpgradeTrait;
use SV\StandardLib\InstallerHelper;

class Setup extends AbstractSetup
{
    use StepRunnerInstallTrait;
    use StepRunnerUpgradeTrait;
    use StepRunnerUninstallTrait;
    use InstallerHelper;

    protected function getTables(): array
    {
        return [
            'table_name' => function ($table) {
                /** @var Create|Alter $table */
                $this->addOrChangeColumn($table, 'xf_user_id', 'int');
                $this->addOrChangeColumn($table, 'username', 'int');
                $this->addOrChangeColumn($table, 'user_token', 'bigint');
                $this->addOrChangeColumn($table, 'last_update', 'int');
                $this->addOrChangeColumn($table, 'account_age', 'int');
                $table->addKey('xf_user_id');
            },
        ];
    }

    protected function getAlterTables(): array
    {
        return [
            'xf_user' => function (Alter $table) {
                $this->addOrChangeColumn($table, 'bm_rank', 'int')->nullable(true)->setDefault(null);
                $this->addOrChangeColumn($table, 'bm_services', 'int')->nullable(true)->setDefault(null);
            },
            'xf_user_option' => function (Alter $table) {
                $this->addOrChangeColumn($table, 'bm_privacy_setting', 'tinyint', 3)->nullable(true)->setDefault(null);
                $this->addOrChangeColumn($table, 'bm_distance_preference', 'tinyint', 3)->nullable(true)->setDefault(null);
            },
        ];
    }

    protected function getRemoveAlterTables(): array
    {
        return [
            'xf_user' => function (Alter $table) {
                $table->dropColumns([
                    'bm_rank',
                    'bm_services'
                ]);
            },
            'xf_user_option' => function (Alter $table) {
                $table->dropColumns([
                    'bm_privacy_setting',
                    'bm_distance_preference'
                ]);
            },
        ];
    }

    public function installStep1(): void
    {
        $sm = $this->schemaManager();

        foreach ($this->getTables() as $tableName => $callback) {
            $sm->createTable($tableName, $callback);
            $sm->alterTable($tableName, $callback);
        }
    }

    public function installStep2(): void
    {
        $sm = $this->schemaManager();

        foreach ($this->getAlterTables() as $tableName => $callback) {
            if ($sm->tableExists($tableName)) {
                $sm->alterTable($tableName, $callback);
            }
        }
    }

    public function uninstallStep1(): void
    {
        $sm = $this->schemaManager();

        foreach ($this->getTables() as $tableName => $callback) {
            $sm->dropTable($tableName);
        }
    }

    public function uninstallStep2(): void
    {
        $sm = $this->schemaManager();

        foreach ($this->getRemoveAlterTables() as $tableName => $callback) {
            if ($sm->tableExists($tableName)) {
                $sm->alterTable($tableName, $callback);
            }
        }
    }
}

In order to ensure your addon cannot be installed unless Standard Library is installed you can accomplish this by doing something like the following in the .json config file:
JSON:
{
    "legacy_addon_id": "",
    "title": "App Name",
    "description": "App Description",
    "version_id": 1000010,
    "version_string": "1.0.0 Alpha",
    "dev": "Rylea Stark",
    "dev_url": "https://github.com/RyleaStark",
    "faq_url": "",
    "support_url": "",
    "extra_urls": {
        "GitHub Repo": "https://github.com/<user>/<repo>"
    },
    "require": {
        "XF": [
            2020900,
            "XenForo 2.2.9"
        ],
        "php": [
            "8.1.5",
            "PHP 8.1.5+"
        ],
        "SV/StandardLib": [
            1110200,
            "Standard Library by Xon v1.11.2+"
        ]
    },
    "require-soft": {
        "SV/StandardLib": [
            1110200,
            "Standard Library by Xon v1.11.2+",
            false
        ]
    },
    "icon": "fas fa-bus-alt"
}
 
Top