How can i get last insert id, look like this :
$user = new User();
$user->name = 'asdf';
$user->save();
echo $user->id;
But inside models in function aftercreate or beforecreate function :
public function beforecreate(){
// last id ?
}
What I'm trying to do is to logs the sql statement into another table.
You could do this in the afterCreate. Please note the exit; for debugging purpose.
public function afterCreate()
{
echo $this->id; // 8
exit;
}
Unfortunately you can not access the id in beforeCreate because the record is not yet created, thus there is no id yet.
If you really need id in beforeCreate you could try to get current max value of the primary key and increment it with 1. But that's a bit hacky and using afterCreate is the preferred option.
Related
Trying to sort my table. The numbers are category_id and they are not sorted by number (1 and 2 are at the bottom of the table), I want to order them.
Controller:
public function fetchcategory(){
$all_categories = HmsBbrCategory::all();
return response()->json([
'all_categories'=>$all_categories,
]);
}
When I try the code below, I get 500 internal server error in my console:
$all_categories = HmsBbrCategory::orderBy('category_id', 'ASC')->all();
What am I doing wrong witht the orderBy code?
Just for reference to know difference between all() and get()
all()
Its a static method so you cant execute additional queries.Only option you have in all() method is you can select columns.
public static function all($columns = ['*'])
{
return static::query()->get(
is_array($columns) ? $columns : func_get_args()
);
}
If we see implementation of that static all() method. Internally it calls get() method
1.all() accept columns as array. Default set to * ,it means all columns selected.
2.Inside of that method ,we can see get() called. So after get we cant call any query operations so its throwing error
get() is Eloquent builder \Illuminate\Database\Eloquent\Builder
Simply you have to update this line
$all_categories = HmsBbrCategory::orderBy('category_id', 'ASC')->all();
into
$all_categories = HmsBbrCategory::orderBy('category_id', 'ASC')->get();
then you will get your result .
I'm creating laravel/vue.js CRUD app and I everything works fine for now but I'm worried about quality of my queries to database after update data.
I am using getAllData() each time when I update row in the database. Now, when I have a few records in database is not a problem to ask server each time and render new list in vue but in when I will have a few thousands of rows it will make my app slow and heavy.
Now I update database like this:
This is part of my vue.js update function:
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="waiting"){
axios.put("http://127.0.0.1:8000/api/payments/"+id
,{pay_status:"payed"}).then((response)=>{
this.getAllData();
}
This is my vue.js getAllData function:
getAllData: function(){
axios.get("http://127.0.0.1:8000/api/payments").then((response)=>{
this.rows = response.data;
});
}
and my PaymentsController:
namespace App\Http\Controllers;
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Faker\Generator;
class PaymentsController extends Controller
{
public function index()
{
$payments = Payments::with('suppliers')->get();
return response($payments, Response::HTTP_OK);
}
}
my updation function:
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
}
Is thare any way to make update in more efficient way, for example get only updated row from database and put it into my existing object with rows? Or maybe i should not worried about it?
Without seeing your logic:
Your controller can return the record:
return response(['payment' => $payment], Response::HTTP_OK);
Your axios method can observe that response and then do a replace on the index (just like you did when getting the index previously)
.then((response) => {
const { payment } = response.data;
this.items[index] = payment;
})
As long as items was instantiated in data as an [] then it's observable.
If you need updated rows for particular time period.
Also, you can do one thing. When user updating the row u can store the unique ID in new table and you can fetch the data through that ID. and then you can delete that ID from new table when you don't need latest updated data.
WHILE UPDATING THE ROW via ID
insert id in new table.
update the record.
if need updated record only >> use back-end conditions as per the
requirement >> Fetch id from new table join with main table.
when you don't need that latest updated record. Delete records from
new table. >> use back-end conditions as per the requirement >>
fetch from main table.
As #Ohgodwhy said, I change my code like this and now it works fine.
update function
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
return response(payments::where('id', $id)->get(), Response::HTTP_OK);
}
axios
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="oczekuje"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"zapłacono"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
} else if (this.rows[index].pay_status=="zapłacono"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"oczekuje"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
}
},
I've set up Yii2 REST API with custom actions and everything is working just fine. However, what I'm trying to do is return some data from the API which would include database relations set by foreign keys. The relations are there and they are actually working correctly. Here's an example query in one of the controllers:
$result = \app\models\Person::find()->joinWith('fKCountry', true)
->where(..some condition..)->one();
Still in the controller, I can, for example, call something like this:
$result->fKCountry->name
and it would display the appropriate name as the relation is working. So far so good, but as soon as I return the result return $result; which is received from the API clients, the fkCountry is gone and I have no way to access the name mentioned above. The only thing that remains is the value of the foreign key that points to the country table.
I can provide more code and information but I think that's enough to describe the issue. How can I encode the information from the joined data in the return so that the API clients have access to it as well?
Set it up like this
public function actionYourAction() {
return new ActiveDataProvider([
'query' => Person::find()->with('fKCountry'), // and the where() part, etc.
]);
}
Make sure that in your Person model the extraFields function includes fKCountry. If you haven't implemented the extraFields function yet, add it:
public function extraFields() {
return ['fKCountry'];
}
and then when you call the url make sure you add the expand param to tell the action you want to include the fkCountry data. So something like:
/yourcontroller/your-action?expand=fKCountry
I managed to solve the above problem.
Using ActiveDataProvider, I have 3 changes in my code to make it work.
This goes to the controller:
Model::find()
->leftJoin('table_to_join', 'table1.id = table_to_join.table1_id')
->select('table1.*, table_to_join.field_name as field_alias');
In the model, I introduced a new property with the same name as the above alias:
public $field_alias;
Still in the model class, I modified the fields() method:
public function fields()
{
$fields = array_merge(parent::fields(), ['field_alias']);
return $fields;
}
This way my API provides me the data from the joined field.
use with for Eager loading
$result = \app\models\Person::find()->with('fKCountry')
->where(..some condition..)->all();
and then add the attribute 'fkCountry' to fields array
public function fields()
{
$fields= parent::fields();
$fields[]='fkCountry';
return $fields;
}
So $result now will return a json array of person, and each person will have attribute fkCountry:{...}
I'm wondering how one can seed in Yii a table once it is created with migration?
I've got a migration with an up-method:
public function up()
{
$this->createTable('users',array('id'=>"pk",
'login'=>'string NOT NULL'));
echo "table 'users' is created.\n";
return true;
}
I've got as well corresponding Users model and its CRUD actions. When I try to execute another migration with an up-method
public function up()
{
$user = new Users;
$user->login = "Bob";
return $user->save();
}
I get the following error:
PHP Error[2]: include(users.php): failed to open stream: No such file or directory
in file MyYiiRoot\yii\framework\YiiBase.php at line 421
I've managed to achieve the desired result by using query builder (by means of insert command), but I hope there is a nicer way out.
Use
public function safeUp()
{
$this->insert('users',array(
'login'=>'Bob'));
}
You can also do update, delete and a host of other actions. Look at http://www.yiiframework.com/doc/api/1.1/CDbMigration for more information
i have a behavior for my models, the behavior has beforeFind, beforeSave, in methods i override user_id, something like:
...
public functio beforeSave() {
$this->owner->user_id = Yii::app()->user->id
}
I have model User, how can i disable behavior for registration new user?
Saving code:
$user = new User();
$user->id = 1332;
$user->field1 = 'data';
$user->save();
but on save i have null in $user->id (because work behavior).
i tried
$user->disableBehaviors();
$user->detachBehavior();
Without result.
Maybe its not right way? I create behaviors for identify users in system (find only user something, save only with user id...), but that if i have new user with full previegies, i should again detach behaviors?
If condition can be changed in future I just pass it as callback parameter into behavior from model.
This give you a bit more control over the condition. Hence, behavior becomes more reusable - if it is used by several models this condition can be unique for each.
Example below is a bit simplified, but you should get the idea.
Behavior:
class SomeBehavior extends CActiveRecordBehavior
{
public $trigger;
public function beforeSave($event)
{
if(!call_user_func($this->trigger))
return;
// do what you need
$this->owner->user_id = Yii::app()->user->id;
}
}
Model:
class SomeModel extends CActiveRecord
{
public function behaviors()
{
$me=$this;
return array(
'some'=>array(
'class'=>'SomeBehavior',
'trigger'=>function() use($me){
return $me->scenario=='some-scenario';
}
)
);
}
}
Also I use PHP 5.3. So, I use closure for trigger callback.
If your PHP version is less than 5.3 - anything callable can be used instead. Check here http://www.php.net/manual/en/function.is-callable.php
Because of behavior is a method, you can declare your own logic inside.
The model knows about its scenario, so there is no problem to return different arrays for different conditions:)
Hope it be helpful for somebody.
You can check Yii::app()-user->isGuest to determine if the user is logged in or not. or you can just try looking for the null. Like this:
if (!Yii::app()->user->isGuest)
$this->owner->user_id = Yii::app()->user->id;
or
if (null !== Yii::app()->user->id)
$this->owner->user_id = Yii::app()->user->id;