Laravel Cashier is not saving stripe data to my DB after a user is created.
When I create a new user and then try to assign a subscription() to that user (or any other user for that matter) the data is being sent to Stripe approriately, as I can see the customer id, plan chosen, etc... But my database user stripe columns do not get updated in my database.
When I remove the code to create() a user and just subscribe a user, the data persists to the database like it should. It only doesn't work after I've created a new user THEN try to subscribe any user.
I'm using Jeffrey Way's Model Validation Package.
$user = $this->userModel->create($input);
if ($user->hasErrors()) {
throw new \Exception($user->getErrors());
}
$this->createStripeSubscription($user->id, $input['creditCardToken']);
private function createStripeSubscription($user_id, $token) {
//$this->userModel->find(1)->subscription('monthly')->create($token); // Doesn't work either
$this->userModel->find($user_id)->subscription('monthly')->create($token);
}
I had similar problem with Ardent validation in Confide.
Overriding saving method of BillableTrait in user model solved the issue.
class User extends ConfideUser implements BillableInterface {
use BillableTrait;
public function saveBillableInstance()
{
$this->forceSave();
}
}
The problem was a conflict with Jeffrey Way's Validation Model package. Or at least the way I was trying to implement it while using Cashier. I decided to abstract out my Validation in it's own class and remove the Validation Model package. All is good.
Related
I have used dektrium/yii2-user in my application.
And there is a method named getID() in User.php of vendor/dektrium and this method can be accessed by Yii::$app->user->getID() and returns id of the logged in user.
However, there is another method named getProfile() whose function is to return complete profile details of currently logged in user. But, this method is giving 500-internal server error.
exception 'yii\base\UnknownMethodException' with message 'Calling unknown method: yii\web\User::getProfile()' in ... ...
I Googled the issue but found nothing... Help me folks..
I believe that you can get the profile of the currently logged in user like this:
Yii::$app->user->identity->profile;
because Yii::$app->user->identity returns the current user - the User object.
You are confusing Yii's web user object with the user model :)
EDIT:
Yii::$app->user is referring to yii\web\User - the application component that manages the user authentication status.
You ask that User component to get the 'identity' which is :
IdentityInterface is the interface that should be implemented by a class providing identity information
In this case, Dektrium User model implements the IdentityInterface and you are able to call getId on it and get the id for the User model.
class User extends ActiveRecord implements IdentityInterface
This code:
Yii::$app->user->identity->profile;
Will return the Profile model data associated with the User
And you can access it's fields directly:
Yii::$app->user->identity->profile->location;
See dektrium\user\models\Profile for details.
People always gets confused about yii\web\User, the IdentityInterface and the User model..
Myself included :p
If you have an instance of an user ($user), you can use the getProfile() function:
$profile = $user->getProfile()->one();
And it returns profile record from that user.
If you don't have an instance of user, but the id ($user_id), you could get an instance of Profile model directly:
$profile = Profile::find()->where(['user_id' => $user_id)->one();
And Yii::$app->user is an interface to the user model defined in your app (dektrium user model in this case): http://www.yiiframework.com/doc-2.0/yii-web-user.html
to sum up:
$user_id = Yii::$app->user->getID();
$profile = Profile::find()->where(['user_id' => $user_id)->one();
Try this one
\app\models\User::findOne(Yii::$app->user->identity->id)->profile;
I'm developing a Laravel web app using Laravel 5.2. My question is very simple... How do I listen to a forceDelete event in order to forceDelete model relations?
I've been looking around the web and S.O. for a few but all the questions/answers I've found where releted to the delete method, and also in the API documentation I haven't found very much...
In my case I have a Registry model and a RegistryDetail model
Registry table
|id|name|surname|....
RegistryDetail table
|id|id_registry|....
I've created for both this boot function:
protected static function boot()
{
parent::boot();
static::deleted(function($registry) {
// Delete registry_detail
$registry->registryDetail->delete();
});
static::restored(function($registry) {
// Restore registry_detail
$registry->registrydetail()->withTrashed()->restore();
});
}
Since both models have SoftDeletes the static::deleted function is called only when the delete() method is called. if I call a forceDelete() method the related model won't be deleted from the database.
If you need more informations let me know.
Thanks in advance
The deleted event should still fire when calling forceDelete(). Inside the deleted() event method, you can check the the forceDeleting protected property via isForceDeleting() to see if you're in a regular delete or a forced delete.
static::deleted(function($registry) {
// Delete registry_detail
if ($registry->isForceDeleting()) {
$registry->registryDetail->forceDelete();
} else {
$registry->registryDetail->delete();
}
});
We are trying to detect the changes in Laravel related models at attribute level, as we have to keep audit trail of all the changes which are made via the application.
We can track the changes via isDirty method on the Eloquent model for single model that is not related to any other model, but there is no way that we can track the changes on the related eloquent models. isDirty doesn't work on related models attributes. Can some one please help us on this?
Update to original question:
Actually we are trying to track changes on the pivot table that has extra attributes as well defined on it. IsDirty method doesn't work on those extra attributes which are defined in the pivot table.
Thanks
As much I understand your question, It's can achieve through Model Event and some sort of extra code with current and relation model.
Laravel Model Events
If you dont want to use any additional stuff, you can just use the Laravel Model Events (that in fact Ardent is wrapping in the hooks). Look into the docs http://laravel.com/docs/5.1/eloquent#events
Eloquent models fire several events, allowing you to hook into various
points in the model's lifecycle using the following methods: creating,
created, updating, updated, saving, saved, deleting, deleted,
restoring, restored.
Whenever a new item is saved for the first time, the creating and
created events will fire. If an item is not new and the save method is
called, the updating / updated events will fire. In both cases, the
saving / saved events will fire.
If false is returned from the creating, updating, saving, or deleting
events, the action will be cancelled:
Finally, reffering to your question you can utilize the above approaches in numerous ways but most obviously you can combine it (or not) with the Eloquent Models' getDirty() api docs here method and getRelation() api docs here method
It will work for example with the saving event.
Model::saving(function($model){
foreach($model->getDirty() as $attribute => $value){
$original= $model->getOriginal($attribute);
echo "Changed";
}
$relations = $model->getRelations();
foreach($relations as $relation){
$relation_model = getRelation($relation);
foreach($relation_model->getDirty() as $attribute => $value){
$original= $relation_model->getOriginal($attribute);
echo "Relation Changed";
}
}
return true; //if false the model wont save!
});
Another Thought might help you. when you saving
save() will check if something in the model has changed. If it hasn't it won't run a db query.
Here's the relevant part of code in Illuminate\Database\Eloquent\Model#performUpdate:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
The getDirty() method simply compares the current attributes with a copy saved in original when the model is created. This is done in the syncOriginal() method:
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
check model is dirty isDirty():
if($user->isDirty()){
// changes have been made
}
Or check certain attribute:
if($user->isDirty('price')){
// price has changed
}
I did not check this code but hopeful to use as your answer by thoughts, if you have any confusion to deal such requirement or something need to optimize or change please let me know.
Just getting to grips with Laravel 4.2 and eloquent. I've been watching the Laravel from Scratch casts on laracasts.com, particularly the lessons on validation and the follow up refactoring. The examples used throughout those lessons deal with a relatively basic user model whereby there are only 2 fields, username and password. My user model contains many more fields and my registration form asks for the user to re-enter/confirm the password they have entered.
It seems to be recommended that the process of validating user input should be done within the model, which makes total sense. So just like that tutorial I have gone ahead and added an isValid method to my model to validate user input on my registration form. I fill my user model based on the input like this:
$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
return Redirect::back()->withInput()->withErrors($this->user->errors);
}
So I've written my rules and got the validation working and I am now ready to save the user's input to the database. However, since I've filled my model with the entire user input, the user model instance now contains an attribute of confirm_password and calling $user->save(); gives me an error (Since I don't have this field in my database table). In addition, since I have just passed in the user input to validate, the password there is not hashed either.
What would be the best approach to take with regards to validating user input VS having the model actually represent the database table? I know there are ways I could get around all this by doing things like moving the validation outside the model and perhaps just let the model store the validations rules etc. but I can looking for advice on the best practice.
Thanks
You may remove it before saving, for example:
$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
return Redirect::back()->withInput()->withErrors($this->user->errors);
}
else {
unset($this->user->attributes['confirm_password']);
$this->user->save();
}
This may work but not the proper way for doing it. You may also use a saving event like:
// Goes in to your model
protected static function boot()
{
parent::boot();
static::saving(function($model) {
unset($model->attributes['confirm_password']);
});
}
Since you are validationg inside your model then you may trigger the validation on saving event, like:
protected static function boot()
{
parent::boot();
static::saving(function($model) {
if($model->isValid()) {
unset($model->attributes['confirm_password']);
return true;
}
return false;
});
}
There are nicer ways to accomplish this same thing.
Restrict your Input values. You can pass Input::all() to your validator and still do this.
$input = Input::only('username', 'password');
// – OR –
$input = Input::except('confirm_password');
Add $fillable to your User model.
class User extends Eloquent {
protected $fillable = array('id', 'name', 'email', 'password');
}
Then you can populate the database from the Input and only the columns in the fillable array will be populated. Make sure you have good validation rules if you try this.
$user = User::create(Input::all());
This will accomplish what you are trying to do without unsetting Input values or adding Model events.
I have two models 'a' and 'b' and a->hasMany('b') and b->belongsTo('a')
So when I create one 'b' this should belongs to exactly one 'a'.
The problem is with the usual Route::resource('b', 'bController') I can just create this 'b' and don't know to which 'a' this belongs.
I tried editing the create() method in bController to create($id) but
Redirect::action('bController#create', $a->id)
Still redirects to /b/create?2 an gives an error
Missing argument 1 for bController::create()
Maybe a bit easier to unserstand when I use phoneand user.
Every phone belongs to one user.
How can I create a phone? How do I give the create() the parameter of the user and still use the Route::resource?
I think you are on a wrong direction because User and Phone are two models and hence a User has many phones so here Phone model is a child model (related) of User class and a Phone can't exist without a User so you only need to create a User through the controller and Phone will be created when the User gets created, for example:
Route::resource('users', 'UserController');
Now assume that you have tow models as User and Phone and the User model has phones method which builds the relationship (phones = User->hasMany('Phone')) and the Phone model has a user method which builds the relationship (user = Phone->belomgsTo('User')).
// User model
class User extends Eloquent {
//...
public function phones()
{
return $this->hasMany('Phone');
}
}
// Phone model
class Phone extends Eloquent {
//...
public function user()
{
return $this->belongsTo('user');
}
}
Now to create a User the store method will be used like this:
// UserController.php
class UserController extends BaseController {
// Other methods
// Creates a User
// URI: /users Method: POST
public function store()
{
// Create a User using User model
$user = User::create(...);
if($user) {
// Initialize/Create a Phone
$phone = new Phone(array(...));
if($phone) {
// Save the Phone and relate with User
$user->phones()->save($phone);
}
}
}
}
This is the basic idea and the final thing is that, a Phone doesn't require a Controller to be created, because it's the part of a User so when you create a new User then create a (or more) Phone from the UserController after you create a User or update a Phone when you update a User.
So if you want to load a User with it's related Phone models then you may do it like this:
$user = User::with('phones')->find(1);
So, when you load a user, you can load all the phones related with that user so during editing of an user; you only need to load a User with related Phone models and pass that model to the view.
To add a new Phone to an existing User you need to edit the User model so you can load a User model with phones and pass that User model to the view for editing. When new Phone being added to the user, you only need to attach that Phone with existing User, that's it. Hope it makes sense.