I have problem with my code in Laravel Framework. What I am trying to do is sell method inside model. The problem is that $variable keeps its value untill next code execution. How I should make it so it's gonna work like I want to?
/// Model method.
public function Sell()
{
$this->UserData->increment('gold', ($this->ItemData->price / 100) * 80);
$this->delete();
return null;
}
///in controller
$user = \Auth::user();
$user_item = UserItems::find(10);
$user_item->Sell();
return $user_item->ItemData->name; /// Returns full data about model even if I deleted it/sold. After next refresh, returns null/error.I want it to return null since beginning.
Even if you have deleted a record from a database by $this->delete(), $user_item variable still holds a reference to the filled model until the script ends or you destroy the variable.
It seems that you want to return a result of the sell() function. In your case it would be
///in controller
$user = \Auth::user();
$user_item = UserItems::find(10);
$user_item->Sell();
return $user_item->Sell();
I don't know what you are trying to do but below code will solve your issue -
/// Model method.
public function Sell()
{
$this->UserData->increment('gold', ($this->ItemData->price / 100) * 80);
$this->delete();
$this->ItemData = $this->ItemData->fresh()
return null;
}
///in controller
$user = \Auth::user();
$user_item = UserItems::find(10);
$user_item->Sell();
return $user_item->ItemData->name; /// Returns full data about model even if I deleted it/sold. After next refresh, returns null/error.I want it to return null since beginning.
Related
I'm building a simple timetracking App using Laravel 5 where I have two Laravel models, one called "User" and one called "Week"
The relationships are pretty simple:
Week.php:
public function user()
{
return $this->belongsTo('App\User');
}
User.php:
function weeks()
{
return $this->hasMany('App\Week');
}
Now, the User.php file also has a simple helper / novelty function called "getCurrentWeek()" that, as the name suggests, returns the current week
function getCurrentWeek()
{
$possibleWeek = $this->weeks->sortByDesc('starts')->all();
if(count($possibleWeek) != 0)
{
return $possibleWeek[0];
}
else
{
return null;
}
}
My problem is: If I create the very first week for a user and attach / relate it to the user like so:
$week = new Week;
//Omitted: Setting so attributes here ...
$week->user_id = $user->id;
$weeks->save()
$user->weeks()->save($week);
And then call the $user->getCurrentWeek(); method, that method returns null, although a new week has been created, is related to the user and has been saved to the database. In my mind, the expected behaviour would be for getCurrentWeek() to return the newly created week.
What am I misunderstanding about Eloquent here / doing just plain wrong?
Relationship attributes are lazy loaded the first time they are accessed. Once loaded, they are not automatically refreshed with records that are added or removed from the relationship.
Since your getCurrentWeek() function uses the relationship attribute, this code will work:
$week = new Week;
// setup week ...
$user->weeks()->save($week);
// $user->weeks attribute has not been accessed yet, so it will be loaded
// by the first access inside the getCurrentWeek method
dd($user->getCurrentWeek());
But, this code will not work:
// accessing $user->weeks lazy loads the relationship
echo count($user->weeks);
// relate a new record
$week = new Week;
// setup week ...
$user->weeks()->save($week);
// $user->weeks inside the method will not contain the newly related record,
// as it has already been lazy loaded from the access above.
dd($user->getCurrentWeek());
You can either modify your getCurrentWeek() method to use the relationship method ($this->weeks()) instead of the attribute ($this->weeks), which will always hit the database, or you can reload the relationship (using the load() method) after adding or removing records.
Change the getCurrentWeek() method to use the relationship method weeks() (updated method provided by #Bjorn)
function getCurrentWeek()
{
return $this->weeks()->orderBy('starts', 'desc')->first();
}
Or, refresh the relationship using the load() method:
// accessing $user->weeks lazy loads the relationship
echo count($user->weeks);
// relate a new record
$week = new Week;
// setup week ...
$user->weeks()->save($week);
// reload the weeks relationship attribute
$user->load('weeks');
// this will now work since $user->weeks was reloaded by the load() method
dd($user->getCurrentWeek());
Just to add to #patricus answer...
After save/create/update, you can also empty all the cached relation data like so:
$user->setRelations([]);
Or selectively:
$user->setRelation('weeks',[]);
After that, data will be lazy loaded again only when needed:
$user->weeks
That way you can continue using lazy loading.
$user->weeks()->save($week); is not needed because you manually attached the week to the user by using $week->user_id = $user->id; and saving it.
You could actually rewrite the whole function to:
function getCurrentWeek()
{
return $this->weeks->sortByDesc('starts')->first();
}
Or
function getCurrentWeek()
{
return $this->weeks()->orderBy('starts', 'desc')->first();
}
Edit:
I made a little proof of concept and it works fine like this:
App\User.php
function weeks()
{
return $this->hasMany('App\Week');
}
function getCurrentWeek()
{
return $this->weeks->sortByDesc('starts')->first();
}
App\Week.php
public function user()
{
return $this->belongsTo('App\User');
}
routes/web.php or App/Http/routes.php
Route::get('poc', function () {
$user = App\User::find(1);
$week = new App\Week;
$week->user_id = $user->id;
$week->starts = Carbon\Carbon::now();
$week->save();
return $user->getCurrentWeek();
});
Result:
{
id: 1,
user_id: "1",
starts: "2016-09-15 21:42:19",
created_at: "2016-09-15 21:42:19",
updated_at: "2016-09-15 21:42:19"
}
Hi I have problem when i tried to save attribute of model to database. I write in OctoberCMS and i have this function:
public function findActualNewsletter()
{
$actualNewsletter = Newsletter::where('status_id', '=', NewsletterStatus::getSentNowStatus())->first();
if (!$actualNewsletter) {
$actualNewsletter = Newsletter::where('send_at', '<=', date('Y-m-d'))->where('status_id', NewsletterStatus::getUnsentStatus())->first();
$actualNewsletter->status_id = NewsletterStatus::getSentNowStatus();
dd($actualNewsletter);
}
return $actualNewsletter;
}
getSentNowStatus()=2;
getUnsentStatus()=1;
dd($actualNewsletter) in my if statement show that status_id = 2 But in database i still have 1. I used this function in afterSave() so i dont need:
$actualNewsletter->status_id = NewsletterStatus::getSentNowStatus();
$actualNewsletter->save();
becosue i have error then i use save in save.
Of course i filled table $fillable =['status_id']. And now i dont know why its not save in database when it go to my if. Maybe someone see my mistake?
If you are trying to modify the model based on some custom logic and then save it, the best place to put it is in the beforeSave() method of the model. To access the current model being saved, just use $this. Below is an example of the beforeSave() method being used to modify the attributes of a model before it gets saved to the database:
public function beforeSave() {
$user = BackendAuth::getUser();
$this->backend_user_id = $user->id;
// Handle archiving
if ($this->is_archived && !$this->archived_at) {
$this->archived_at = Carbon\Carbon::now()->toDateTimeString();
}
// Handle publishing
if ($this->is_published && !$this->published_at) {
$this->published_at = Carbon\Carbon::now()->toDateTimeString();
}
// Handle unarchiving
if ($this->archived_at && !$this->is_archived) {
$this->archived_at = null;
}
// Handle unpublishing, only allowed when no responses have been recorded against the form
if ($this->published_at && !$this->is_published) {
if (is_null($this->responses) || $this->responses->isEmpty()) {
$this->published_at = null;
}
}
}
You don't have to run $this->save() or anything like that. Simply modifying the model's attributes in the beforeSave() method will accomplish what you desire.
I have a function that I use to get the user id of Auth component. It works fine without use return json_encode. The problem is that I need this works with json_encode because I get values from ajax request.
Using json_encode it always return null to id and I can't understand why does it occur. The problem is with the function indexAjax() below.
How could I use $this->Auth->user("id") with json_encode and it not return null ?
Trying.
//using $this->set it works fine
public function index() {
$id = $this->Auth->user("id");
$empresas = $this->Empresa->find('all', array(
'fields'=>array("id", "nomeFantasia", "cnpj",
"telefone1", "telefone2", "celular", "aberto"),
'conditions'=>array("users_id = "=> $id)
));
debug($id) or die;
//$this->set(compact('empresas'));
}
//with json_encode always return null
public function indexAjax() {
$this->autoRender = false;
$id = $this->Auth->user("id");
$empresas = $this->Empresa->find('all', array(
'fields'=>array("id", "nomeFantasia", "cnpj",
"telefone1", "telefone2", "celular", "aberto"),
'conditions'=>array("users_id = "=> $id)
));
return json_encode($id);
}
solved the problem. My solution was when user make login I get the user id and write in session so when I need this id I get from session directly and not from AuthComponent.
It works.
I'm new to laravel, and this is the first framework I'm learning in any language, anyway,
I deleted some records using :
public function getForceLogOut()
{
$input = Input::all();
$e = $input['email'];
echo $e;
DB::select(DB::raw("DELETE FROM active_users WHERE email = '$e'"));
}
But the query executed through the eloquent model returns the object anyway, even though it has been actually been deleted (checked the table in phpMyAdmin)
public static function isLoggedIn()
{
$email = Auth::user()->email;
//$user = ActiveUser::where("email",$email); <== RETURNS THE OBJECT
$user = DB::select(DB::raw("SELECT * fROM active_users where email = '$email'")); // <== WORKS FINE
if ($user) {
return true;
} else {
Auth::logout();
return false;
}
}
Why is this happening? Doesn't eloquent model query the database and works on cached records or something similar?
EDIT: yes, as pointed out, it returns the QueryBuilder object! My mistake.
You are doing this:
$user = ActiveUser::where("email",$email);
which returns you a QueryBuilder, QueryBuilders are used by Laravel to prepare your queries while you're constructing them through your Eloquent model.
If you want to get the result from your database, you should do:
$user = ActiveUser::where("email",$email)->first();
which should return you the query result, or null if the record doesn't exist.
Okay, so I have this snippet of code in a controller. However, it's all DB driven and should really be in model - I get that. However, as you can see in the IF statement, I need to pass along $data to my view. Based on the outcome. I tried pasting this chuck of coding in a method in my model (calling the model method via controller), however the $data[update_prompt] string is not getting called by the view...
How would I translate this code into a model - sending the $data values back to my controller to embed in my view?
// show appropriate upgrade message if user has free account
$id = $this->session->userdata('user_id');
$this->db->select('subscription'); // select the subscription column
$this->db->where('id', $id); //find id in table that matches session id
$query = $this->db->get("subscriptions"); // connect to this database
$subscribe = $query->result_array(); //returns the result of the above
if($subscribe[0]['subscription'] == 'freebie') // if subscription column equals 'freebie' in the $subscribe array, do this:
{
$data['update_prompt'] = $this -> load -> view('shared/upgrade_subscription', '', TRUE); // adds view within view, $update_prompt
}
else
{
$data['update_prompt'] = '';
}
You would add a function in your model, like so:
public function myModelFunction($id) {
//we return row as we are looking up by primary key and are guaranteed only one row
return $this->db->select('subscription')
->where('id', $id)
->get('subscriptions')
->row();
}
Then, in your controller:
public function myControllerFunction() {
$subscribe = $this->my_model->myModelFunction($this->session->userdata('id'));
if($subscribe->subscription == 'freebie') // if subscription column equals 'freebie' in the $subscribe array, do this:
{
$data['update_prompt'] = $this -> load -> view('shared/upgrade_subscription', '', TRUE); // adds view within view, $update_prompt
}
else
{
$data['update_prompt'] = '';
}
}