I am having an issue with the BIllable trait when using a custom primary key of user_id. The issue seems to have been introduced in #337. The getForeignKey method in Billable assumes that the primary key is id and prepends user_ to it. However if I use user_id I end up with user_user_id which fails.
For now I have overridden the method in the user model to just return the unmodified key.
SQLSTATE[42703]: Undefined column: 7 ERROR: column subscriptions.user_user_id does not exist
LINE 1: select * from "subscriptions" where "subscriptions"."user_us...
^ (SQL: select * from "subscriptions" where "subscriptions"."user_user_id" = 1 and "subscriptions"."user_user_id" is not null order by "created_at" desc)
in Connection.php (line 647) at Connection->runQueryCallback('select * from "subscriptions" where "subscriptions"."user_user_id" = ? and "subscriptions"."user_user_id" is not null order by "created_at" desc', array(1), object(Closure))
in Connection.php (line 607) at Connection->run('select * from "subscriptions" where "subscriptions"."user_user_id" = ? and "subscriptions"."user_user_id" is not null order by "created_at" desc', array(1), object(Closure))
in Connection.php (line 326) at Connection->select('select * from "subscriptions" where "subscriptions"."user_user_id" = ? and "subscriptions"."user_user_id" is not null order by "created_at" desc', array(1), true)
in Builder.php (line 1710) at Builder->runSelect()
in Builder.php (line 1695) at Builder->get(array('*'))
in Builder.php (line 462) at Builder->getModels(array('*'))
in Builder.php (line 446) at Builder->get()
in HasMany.php (line 16) at HasMany->getResults()
in HasAttributes.php (line 407) at Model->getRelationshipFromMethod('subscriptions')
in HasAttributes.php (line 386) at Model->getRelationValue('subscriptions')
in HasAttributes.php (line 316) at Model->getAttribute('subscriptions')
in Model.php (line 1265) at Model->__get('subscriptions')
in Billable.php (line 202) at User->subscription('main')
in Billable.php (line 180) at User->subscribed('main')
in HomeController.php (line 33) at HomeController->index() at call_user_func_array(array(object(HomeController), 'index'), array())
in Controller.php (line 55) at Controller->callAction('index', array())
in ControllerDispatcher.php (line 44) at ControllerDispatcher->dispatch(object(Route), object(HomeController), 'index')
in Route.php (line 203) at Route->runController()
in Route.php (line 160) at Route->run()
in Router.php (line 574) at Router->Illuminate\Routing\{closure}(object(Request))
in Pipeline.php (line 30) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in SubstituteBindings.php (line 41) at SubstituteBindings->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in Authenticate.php (line 43) at Authenticate->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in VerifyCsrfToken.php (line 65) at VerifyCsrfToken->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in ShareErrorsFromSession.php (line 49) at ShareErrorsFromSession->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in StartSession.php (line 64) at StartSession->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in AddQueuedCookiesToResponse.php (line 37) at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in EncryptCookies.php (line 59) at EncryptCookies->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in Pipeline.php (line 102) at Pipeline->then(object(Closure))
in Router.php (line 576) at Router->runRouteWithinStack(object(Route), object(Request))
in Router.php (line 535) at Router->dispatchToRoute(object(Request))
in Router.php (line 513) at Router->dispatch(object(Request))
in Kernel.php (line 176) at Kernel->Illuminate\Foundation\Http\{closure}(object(Request))
in Pipeline.php (line 30) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in Debugbar.php (line 51) at Debugbar->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in TransformsRequest.php (line 30) at TransformsRequest->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in TransformsRequest.php (line 30) at TransformsRequest->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in ValidatePostSize.php (line 27) at ValidatePostSize->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in CheckForMaintenanceMode.php (line 46) at CheckForMaintenanceMode->handle(object(Request), object(Closure))
in Pipeline.php (line 148) at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
in Pipeline.php (line 53) at Pipeline->Illuminate\Routing\{closure}(object(Request))
in Pipeline.php (line 102) at Pipeline->then(object(Closure))
in Kernel.php (line 151) at Kernel->sendRequestThroughRouter(object(Request))
in Kernel.php (line 116) at Kernel->handle(object(Request))
in index.php (line 53) at require('/Users/user/laravel/project/public/index.php')
in server.php (line 133)
I don't think this is really a bug but I feel like getForeignKey() needs a mention in the documentation, surely its not uncommon for people to use different primary/foreign key naming conventions.
@jcloutz What did you use to override this issue? I am also having this issue and can't figure out a solution.
@kiehlinit - what is your table and primary key called?
@MichaelHoughton my table is called users and my primary key is user_id
@kiehlinit - what is the foreignKey in your subscriptions table? e.g. is it user_id or something different?
@MichaelHoughton id
I used default cashier.
CREATE TABLE subscriptions (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
user_id int(11) NOT NULL,
name varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
stripe_id varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
stripe_plan varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
quantity int(11) NOT NULL,
trial_ends_at timestamp NULL DEFAULT NULL,
ends_at timestamp NULL DEFAULT NULL,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@kiehlinit - I think you missed what I mean - can you share your migration for the subscriptions table, so I can check the foreign Key. The id field will be your primary key.
@MichaelHoughton I'm not using migrations as I rewrote my system in laravel from a non-framework based app.
@kiehlinit - can you share the SQL of your subscriptions table then?
@MichaelHoughton
CREATE TABLE subscriptions (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
user_id int(11) NOT NULL,
name varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
stripe_id varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
stripe_plan varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
quantity int(11) NOT NULL,
trial_ends_at timestamp NULL DEFAULT NULL,
ends_at timestamp NULL DEFAULT NULL,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@kiehlinit - you need to change the field:
user_id int(11) NOT NULL
to
user_user_id int(11) NOT NULL
This will solve the error.
If you have an edge case, you can extend the Laravel\Cashier\Subscription and define your own Subscription and modify the user method as well.
public function user()
{
$model = getenv('STRIPE_MODEL') ?: config('services.stripe.model', 'User');
$model = new $model;
return $this->belongsTo(get_class($model), 'what_ever');
}
In your User model
public function subscriptions()
{
return $this->hasMany(Subscription::class, 'what_ever')->orderBy('created_at', 'desc');
}
So if I get this right your primary key on the users table is user_id and your relation column on the subscriptions table is user_id as well? In that case isn't it safe to assume your foreign key name will always be user_id? Just overwrite the getForeignKey method to return your own implementation for the User model.
/**
* Get the default foreign key name for the model.
*
* @return string
*/
public function getForeignKey()
{
return $this->getKeyName();
}
Let me know if this is still an issue after this fix ^
@driesvints thank you Man馃憤馃憤馃憤
Most helpful comment
So if I get this right your primary key on the users table is
user_idand your relation column on the subscriptions table isuser_idas well? In that case isn't it safe to assume your foreign key name will always beuser_id? Just overwrite thegetForeignKeymethod to return your own implementation for the User model.