MODX3: Package installer - can't get database tables resolver to run properly

I’m refactoring my GoodNews add-on as a standalone version for MODX3 only. I’m at the finish line but I can’t get the database tables resolver to run properly!

Installing the package I get the following errors:

Could not load class: Bitego\GoodNews\Model\GoodNewsMailingMeta from mysql.bitego\goodnews\model\goodnewsmailingmeta
Could not get table name for class: 
Could not load class: Bitego\GoodNews\Model\GoodNewsMailingMeta from mysql.bitego\goodnews\model\goodnewsmailingmeta

Could not load class: Bitego\GoodNews\Model\GoodNewsRecipient from mysql.bitego\goodnews\model\goodnewsrecipient
Could not get table name for class: 
Could not load class: Bitego\GoodNews\Model\GoodNewsRecipient from mysql.bitego\goodnews\model\goodnewsrecipient

Could not load class: Bitego\GoodNews\Model\GoodNewsSubscriberMeta from mysql.bitego\goodnews\model\goodnewssubscribermeta
Could not get table name for class: 
Could not load class: Bitego\GoodNews\Model\GoodNewsSubscriberMeta from mysql.bitego\goodnews\model\goodnewssubscribermeta
...

This is the resolver:
The same code runs in a bootstrap script (without the xPDOTransport part) to setup dev environment without problems but not in resolver…

<?php

/**
 * This file is part of the GoodNews package.
 *
 * @copyright bitego (Martin Gartner)
 * @license GNU General Public License v2.0 (and later)
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use MODX\Revolution\modX;
use xPDO\Transport\xPDOTransport;

/**
 * Resolve/create database tables
 *
 * @package goodnews
 * @subpackage build
 */

$tables = [
     Bitego\GoodNews\Model\GoodNewsMailingMeta::class,
     Bitego\GoodNews\Model\GoodNewsRecipient::class,
     Bitego\GoodNews\Model\GoodNewsSubscriberMeta::class,
     Bitego\GoodNews\Model\GoodNewsSubscriberLog::class,
     Bitego\GoodNews\Model\GoodNewsGroup::class,
     Bitego\GoodNews\Model\GoodNewsGroupMember::class,
     Bitego\GoodNews\Model\GoodNewsCategory::class,
     Bitego\GoodNews\Model\GoodNewsCategoryMember::class,
     Bitego\GoodNews\Model\GoodNewsProcess::class,
];

if ($object->xpdo) {
    $modx = &$object->xpdo;

    switch ($options[xPDOTransport::PACKAGE_ACTION]) {
        case xPDOTransport::ACTION_INSTALL:
        case xPDOTransport::ACTION_UPGRADE:
            $modx->log(modX::LOG_LEVEL_INFO, 'Database tables resolver - creating database tables...');
            $modx->log(modX::LOG_LEVEL_WARN, 'Existing tables will be skipped!');

            $manager = $modx->getManager();
            $count = 0;
            foreach ($tables as $table) {
                $tableName = $modx->getTableName($table);
                // Do not report table creation detailes
                $prevLogLevel = $modx->setLogLevel(modX::LOG_LEVEL_ERROR);
                $created = $manager->createObjectContainer($table);
                $modx->setLogLevel($prevLogLevel);
                if ($created) {
                    ++$count;
                    $modx->log(modX::LOG_LEVEL_INFO, '-> added database table: ' . $tableName);
                } else {
                    $modx->log(modX::LOG_LEVEL_INFO, '-> database table ' . $tableName . ' already exists - skipped!');
                }
            }
            break;

        case xPDOTransport::ACTION_UNINSTALL:
            $modx->log(
                modX::LOG_LEVEL_WARN,
                'Database tables resolver - database tables will not be uninstalled to prevent data loss. ' .
                'Please remove manually.'
            );
            break;
    }
}
unset($tables, $table, $count);
return true;

Do I still need to use $modx->addPackage?

Try changing this:

$modx = &$object->xpdo;

to this:

$modx = &$transport->xpdo;

For packages meant to install in both MODX 2 and MODX 3, I’ve found this to be necessary for some older packages:

if ($transport) {
    $modx = &$transport->xpdo;
} else {
    $modx = &$object->xpdo;
}

Thanks Bob, but this didn’t work.

I finally solved it by creating a resolver which includes the bootstrap.php of my package (before the tables resolver) and so the installer knows all classes to create the tables!

Here is the code (maybe its useful for others too):

<?php

/**
 * This file is part of the GoodNews package.
 *
 * @copyright bitego (Martin Gartner)
 * @license GNU General Public License v2.0 (and later)
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use xPDO\Transport\xPDOTransport;

/**
 * Include bootstrap when installing the package
 *
 * @package goodnews
 * @subpackage build
 */

if ($object->xpdo) {
    $modx = &$object->xpdo;
    $success = true;

    switch ($options[xPDOTransport::PACKAGE_ACTION]) {
        case xPDOTransport::ACTION_INSTALL:
            $corePath = $modx->getOption(
                'goodnews.core_path',
                null,
                $modx->getOption('core_path', null, MODX_CORE_PATH) . 'components/goodnews/'
            );
            $bootstrap = $corePath . 'bootstrap.php';
            if (file_exists($bootstrap)) {
                $namespace = [];
                $namespace['path'] = $corePath;
                require $bootstrap;
            } else {
                $success = false;
                $modx->log(modX::LOG_LEVEL_ERROR, 'Could not include bootstrap.php from path: ' . $corePath);
            }
    }
}
unset($corePath, $bootstrap);
return $success;

I’m glad you got it sorted. You might want to make that change from $object to $transport anyway. According to Jason, that’s how we should have been doing it all along.

1 Like

This topic was automatically closed 2 days after discussion ended and a solution was marked. New replies are no longer allowed. You can open a new topic by clicking the link icon below the original post or solution and selecting “+ New Topic”.