Skip to content

Upgrade guide v10.x to v11.x

Luke Walsh edited this page Dec 18, 2022 · 1 revision

This is a (probably uncomplete) upgrade guide. Please provide some feedback from your own experiences.

📦 Update composer

At the moment of writing, Laravel's latest version was v7.7.1 and osiset/laravel-shopify was v11.4.0.

Laravel

Please upgrade your Laravel version first! See the Laravel docs.

You can check your current Laravel version with command: php artisan --version.

Also check your PHP version!

Osiset/laravel-shopify package

Rename the package in composer.json:

"ohmybrew/laravel-shopify": "^10.3" => "osiset/laravel-shopify": "^11.4"

And do a composer update.

🔧 Configuration

Publish new files from the package: php artisan vendor:publish And choose the number of the provider: Osiset\ShopifyApp\ShopifyAppProvider

New files will be published to your app but the existing files won't be overwritten! You have to manually check those files. Below, you find some crucial files that need your attention.

Models

One crucial change is that app/Models/Shop.php is no longer used. We now put all the shop info into the Laravel User model, which is normally located in app/User.php or app/Models/User.php.

You User model should look like this:

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Osiset\ShopifyApp\Contracts\ShopModel as IShopModel;
use Osiset\ShopifyApp\Traits\ShopModel;

class User extends Authenticatable implements IShopModel
{
    use Notifiable;
    use ShopModel;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
}

Please make sure that you also copy all the new logic from your Shop model to your User model like relationships to other models. Like e.g. Settings.

Change your SHOPIFY_SHOP_MODEL in your environment files to \App\User.

And as last part of this section, replace all code occurences from App\Models\Shop to App\User.

As a tip, you can replace usages like use App\Models\Shop; into use App\User as Shop; With this change, you're still using the Shop name instead of changing all your occurences in your class.

config/shopify-app.php

Copy vendor/osiset/laravel-shopify/src/ShopifyApp/resources/config/shopify-app.php to config/shopify-app.php and make sure all settings are correct for your app.

Pay attention to your webhooks and scripttags. The original file doesn't have default installed webhooks or scripttags.

Also the key config('shopify-app.shop_model') has been removed. Please change all usages with env('SHOPIFY_SHOP_MODEL').

Views

The package will add some new views in your package for auth, billing and partials. The other views, you have to check manually which views have changed parameters or content.

Like the shopOrigin parameter in resources/views/vendor/shopify-app/layouts/default.blade.php has been changed from ShopifyApp::shop()->shopify_domain to Auth::user()->name.

Homecontroller

You should use the HomeController trait in your HomeController.

use Osiset\ShopifyApp\Traits\HomeController as HomeControllerTrait;

class HomeController extends Controller
{
    use HomeControllerTrait;

    ...
}

Jobs

Like early said: take a look at your webhooks in config/shopify-app.php. And make sure your code is using or extending the Osiset package.

You have to update the constructor of your webhook job. the first argument is from the type Osiset\ShopifyApp\Objects\Values\ShopDomain and second part is your data.

Please review this at \Osiset\ShopifyApp\Traits\WebhookController trait.

Kernel

Edit the route middlewares in your app/Http/Kernel.php.

'auth.shopify' => \Osiset\ShopifyApp\Http\Middleware\AuthShopify::class,
'auth.webhook' => \Osiset\ShopifyApp\Http\Middleware\AuthWebhook::class,
'auth.proxy' => \Osiset\ShopifyApp\Http\Middleware\AuthProxy::class,
'billable' => \Osiset\ShopifyApp\Http\Middleware\Billable::class,

Middleware

You can remove the \App\Http\Middleware\AuthShop class because this is now handled by the package middleware.

🗃 Database

!!!Before your start, make sure you have a database dump as a backup!!!

The database scheme has changed a bit.

First, have a look at the manual_migrations key in config/shopify-app.php. You have to choose whether you want to migrate the app manually or not.

If not, the migration from the Osiset package will run automatically and may will end up in a big mess with your previous migrations. This option is nice for new created apps, but not when you want to upgrade from v10.3.1.

If you want to manually do the migrations by yourself (recommended), add SHOPIFY_MANUAL_MIGRATIONS to your environment files and set it on true.

Mutation: Type column

The column type for tables plans and charges are changed from type integer to string. Add this migration by doing php artisan make:migration modify_type_type in your terminal and paste below code:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ModifyTypeType extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('plans', function (Blueprint $table) {
            $table->string('type')->change();
        });

        Schema::table('charges', function (Blueprint $table) {
            $table->string('type')->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('plans', function (Blueprint $table) {
            $table->integer('type')->change();
        });

        Schema::table('charges', function (Blueprint $table) {
            $table->integer('type')->change();
        });
    }
}

Mutation: expires_on in charges table

The charges table requires a new column expires_on. Create the migration: php artisan make:migration add_expires_on_to_charges_table.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddExpiresOnToChargesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->timestamp('expires_on')->nullable()->after('cancelled_on');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->dropColumn(['expires_on']);
        });
    }
}

Mutation: interval in charges table

The charges table requires a new column interval. Create the migration: php artisan make:migration add_interval_column_to_charges_table.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddIntervalColumnToChargesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->string('interval')->nullable()->after('price');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->dropColumn(['interval']);
        });
    }
}

Mutation: User table

Since we use the Laravel's User model instead of a Shop model, we need to create some extra columns.

Create migration: php artisan make:migration add_shop_columns_to_users_table

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddShopColumnsToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('shopify_grandfathered')->default(false);
            $table->string('shopify_namespace')->nullable(true)->default(null);
            $table->boolean('shopify_freemium')->default(false);
            $table->integer('plan_id')->unsigned()->nullable();

            $table->softDeletes();

            $table->foreign('plan_id')->references('id')->on('plans');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropForeign('users_plan_id_foreign');
            $table->dropColumn([
                'shopify_grandfathered',
                'shopify_namespace',
                'shopify_freemium',
                'plan_id',
            ]);

            $table->dropSoftDeletes();
        });
    }
}

Mutation: Shop to User

Some tables need to change their column names from shop_id to user_id like the charges table.

Create migration: php artisan make:migration modify_shop_id_column_for_charges_table

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ModifyShopIdColumnForChargesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->renameColumn('shop_id', 'user_id');
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->dropForeign(['shop_id']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('charges', function (Blueprint $table) {
            $table->renameColumn('user_id', 'shop_id');
            $table->dropForeign(['user_id']);
            $table->foreign('shop_id')->references('id')->on('shops')->onDelete('cascade');
        });
    }
}

Make sure all your other tables have updated their shop_id reference to the user_id reference! Also the Models!

Important Note: If you get an error like Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails check that user_id is fillable on the Model. Also if could be that you need to run the data copy from the Shop table to the User table before this migration. This is usually because you have charges already in the charges table and you can add a foreign key to user_id for those charges because the user_id does not exist in the user table.

You could run this the Shopto User SQL mentioned below before running the ModifyShopIdColumnForChargesTable migration. Also, backup your database.

Migration: remove unique index on email

Because email addresses should be unique in a users table, we have a unique index on the email column.

If you think about it, multiple shops can have the same email address. So we need to remove the unique index first before inserting data from the shop table.

Create migration: php artisan make:migration modify_email_index_for_users_table

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ModifyEmailIndexForUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropUnique('users_email_unique');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->unique('email');
        });
    }
}

Execute the migrations

After you added all above migrations, let's do the migration command: php artisan migrate

MySQL: Move data from shops into users

Use the following SELECT INSERT statement to move data from the shops table into the users table with their respective columns. Keeping the IDs the same will be smoother.

INSERT INTO users (id, name, email, password, created_at, updated_at, shopify_grandfathered, shopify_freemium, plan_id, deleted_at)
SELECT id, shopify_domain, email, shopify_token, created_at, updated_at, grandfathered, freemium, plan_id, deleted_at FROM shops;

Status and type to uppercase

We need to update the status and type columns in the charges table and type in plans table. Their data should be converted to uppercase.

Use below query to update the status in the charges table to uppercase.

UPDATE charges SET status = UPPER(status);

For the type column in charges and plans table, you should first check the ID of the type in \Osiset\ShopifyApp\Objects\Enums\ChargeType.

For example, if you have an app with recurring charges, please insert below queries:

UPDATE plans set type = 'RECURRING' where type = 1;
UPDATE charges set type = 'RECURRING' where type = 1;

Remove Shop table (optional)

Since we use the User model, the Shop model can be removed from code and database. As a personal preference, I don't remove this code and table because I still want it as a kind of backup.

🎨 Update namespaces

As last part, you should check all your existing code on namespacings.

Shop

Update ShopifyApp::shop() to Auth::user().

Be aware that shopify_domain has been changed to name like:

Shop::where('shopify_domain', 'my_store');
=>
User::where('name', 'my_store');

OhMyBrew

Check every reference to the OhMyBrew package and try to change it in the Osiset namespace. Original namespace received a copyright notice and had to migrate.

📚 Feedback

Feel free to add some more best practices in a PR or correct the content.

Welcome to the wiki!

Please see the homepage for a list of relevant pages.

Clone this wiki locally