How to use triggers in laravel? - mysql

My code, using PHP artisan make: migration create_trigger command
public function up()
{
DB::unprepared('
CREATE TRIGGER roll_no BEFORE INSERT ON `students` FOR EACH ROW
BEGIN
SET #roll_num = IFNULL((substring((SELECT student_roll_no FROM students WHERE
class_code = NEW.class_code ORDER BY created_at DESC LIMIT 1),-2) + 1), `1`),
NEW.student_roll_no = CONCAT(
YEAR(CURRENT_DATE),
NEW.class_code,
IF (#roll_num < 10, CONCAT(`0`, #roll_num), #roll_num)
)
END;
');
}

You don't need to create a migration for a model event. Laravel eloquent has multiple events such as retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored that you can easily use them.
first, you should create Observer for your model like this
php artisan make:observer UserObserver --model=User
in the UserObserver you can listen to any event that you like such as:
class UserObserver
{
/**
* Handle the User "created" event.
*
* #param \App\User $user
* #return void
*/
public function created(User $user)
{
//
}
/**
* Handle the User "updated" event.
*
* #param \App\User $user
* #return void
*/
public function updated(User $user)
{
//
}
}
after that you should register your observer to model in app/providers/AppServiceProvider boot method such as:
public function boot()
{
User::observe(UserObserver::class);
}
for more detail visit Laravel documentation.

try this:
please check your SQL syntax
DB::unprepared('CREATE TRIGGER roll_no BEFORE INSERT ON `students` FOR EACH ROW
BEGIN
SET #roll_num = IFNULL((substring((SELECT student_roll_no FROM students WHERE class_code = NEW.class_code ORDER BY created_at DESC LIMIT 1),-2) + 1), `1`),
NEW.student_roll_no = CONCAT(YEAR(CURRENT_DATE)),
NEW.class_code,
IF (#roll_num < 10,
CONCAT(`0`, #roll_num),
#roll_num
)
END');
for example please check this link :
[https://itsolutionstuff.com/post/how-to-add-mysql-trigger-from-migrations-in-laravel-5example.html]1
i hope help you

For this type of operation, laravel makes some technique similar to trigger(event).
If you have multiple events then use Observer otherwise you can choose this solution.
// inside your model
public function boot()
{
parent::boot();
// beforeCreate
self::creating(function($model) {
// do something with your $model before saving....
// return true or the save will cancel....
return true;
});
// afterCreate
self::created(function($model) {
// do something with your $model after saving....
// return true or the save will cancel....
return true;
});
}

Related

Laravel Model get next increment ID when the Table linked with Model is Non-AutoIncrement

As I mentioned in Question, the current Laravel 6.0 project I am working on has bit weird DB setup, where the Model's(the MainModel here) MySQL table has been set with AutoIncrement as NULL. And client won't allow to change the Table's definition at all.
I want to reliably find the next and previous IDs of the Model(since I can't find from table as AutoIncrement is set to NULL) before inserting record, so that I can make an entry of relevant record(for eg. image(s) of a testimonial/faq or any WYSIWYG content field) into another referential table first, by correctly inserting the main Model's ID into the refrential ID field of that another table.
Currently I have this in my main Model, but the next method doesn't reliably return the exact incremented ID consistently:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Te7aHoudini\LaravelTrix\Traits\HasTrixRichText;
class [MainModel] extends Model
{
use HasTrixRichText;
protected $guarded = [];
public $timestamps = false;
protected $primaryKey = 'id';
protected $connection = '[connection1]';
protected $table = '[main_table]';
protected $fillable = ['id', '[titlefield]', '[wysiwyg_field]'];
/**
* Setup model event hooks
*/
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->id = $model->max('id') + 1;
});
}
/**
* Get next available Faq Id
*/
public function next()
{
return ++$this->id;
}
}
Any help is appreciated...
As I understand you are confused about how to call statically model queries. You can achieve the same logic by using a static self-reference static.
public static function next()
{
return static::max('id') + 1;
}
This would be equivalent to.
MainModel::max('id');
Bonus to make it a transaction to avoid id clashing. This can lock the database in fun ways, but will avoid you have the same ids, something similar to this, very simple example.
DB::transaction(function () {
$id= MainModel::next();
$newModel = MainModel::create(['id' => $id]);
});
As I understanding, in order to get the next increment id, you need to call the following line.
Model::lastest()->first()

How to exchange values between 2 records at unique column

How to exchange the values in the Unique column of two records?
like below Model
User
id
name
code // this is unique
What I want to do is like...
$user1 = User::find(1);
$user2 = User::find(2);
DB::Transaction();
try {
$user1->code = $user2->code;
$user2->code = $user1->code;
$user1->save();
$user2->save();
} catch()...
of course, I know this code doesn't work by constraint violation error.
Anyway,I want to exchange UserA's code and UserB's code.
But I don't know the best way.
Any one knows?
I tried this code,and it worked.but it seems little dirty.
$user1 = User::find(1);
$user2 = User::find(2);
DB::Transaction();
try {
$user1_code_temp = $user1->code;
$user2_code_temp = $user2->code;
$user1->code = rand();
$user1->save();
$user2->code = $user1_code_temp;
$user2->save();
$user1->code = $user2_code_temp
$user1->save();
} catch()...
What you are doing is correct. And I personally would prefer it being this way as it is more readable what you are doing. You could disable unique checks in mysql temporarily but I would not recommend that.
To clean up the code, you can add this as a method in users model :
<?php
// Inside User.php model
/**
* Exchange user code
*
* #param User $user
*
* #return void
*/
public function exchangeCode(User $user){
$code1 = $this->code;
$code2 = $user->code;
$this->setCode(rand(6));
$user->setCode($code1);
$this->setCode($code2);
return $this;
}
/**
* Set Code
*
* #param string $code
*
* #return void
*/
public function setCode($code)
{
$this->code = $code;
$this->save();
return $this;
}
// And then in controller
$user1->exchangeCode($user2);
On your model define a
protected $primaryKey = 'code';

Laravel Autocomplete using foreign key to show data from another table

i have created an auto complete search box in controller of 'booking' table successfully , but i want the auto complete search box to show data from another table 'patient' that have a one to many relationship with "booking" table according to a specific condition using 'where' condition ,
This is the Booking Controller that i add autocomplete in it:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Booking;
use App\Patient;
use App\User;
use Session;
use DB;
use Auth;
use Input;
class BookingController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$search = \Request::get('search');
$bookings = Booking::whereHas('patient', function ($query) use ($search) {
$query->where('patient_name', 'like', '%' . $search . '%');
})->where('status','=', null)->whereHas('patient', function ($query){
$query->where('company_id','=' ,Auth::user()->company_id);
})->paginate(10);
return view('booking.index')->withBookings($bookings);
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function autoComplete(Request $request) {
$query = $request->get('term','');
$bookings=Booking::whereHas('patient', function ($query){
$query->where('company_id','=' ,Auth::user()->company_id);
})->$data=array();
foreach ($bookings as $booking) {
$data[]=array('value'=>$booking->patient->patient_name,'id'=>$booking->id);
}
if(count($data))
return $data;
else
return ['value'=>'No Result Found','id'=>''];
}
and this is the Booking Model :
class Booking extends Eloquent
{
public function patient()
{
return $this->belongsTo('App\Patient');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
and this is the patient Model:
class Patient extends Eloquent
{
public function booking()
{
return $this->hasMany('App\Booking');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
and i used this code in view :
{!! Form::text('search_text', null, array('placeholder' => 'Search Text','class' => 'form-control','id'=>'search_text')) !!}
i want to show data from "patient" table and there is a one to many relationship between "booking" and "patient" table and i have successfully made a search box to search in patient table as you can see in index function , but i dont know to show data from "patient" table using where condition to show patient_name that his company_id equal Authenticated user company_id
Sorry for my Bad Language .

Mysql View in Laravel 5.2

This might be simple for someone. But for me I am totally lost. Can anyone give me a heads up for using Mysql View in Laravel 5. I've been searching for relevant post for a while but not a clue except:
DB::statement("Create View")
DB::statement("Drop View")
But this doesn't ring a bell. Any help, any clue, any guide is appreciated.
Thank in advance
My Scenario
I have an employee table with other tables that holds various attributes of the employee separately such as Appointment, posting,health, family etc etc. Most of these tables has one property Is_current to represent the current record of the employee. So whenever I want to display employee profile with latest record or retrieve some latest record from some of these tables, I don't want to retrieve from each an every table one by one. I just want to compile the latest record in a view and retrieve from it whenever I want.
I hope you understand my requirements and sorry for my bad english
I use views all the time for reporting purposes as I can create a denormalized View and then use the power of Models with Scopes and mutators. I wrote an article on how I manage MySQL Views.
# Create a new migration
php artisan make:migration create_employees_record_view
# Update the migration
<?php
use Illuminate\Database\Migrations\Migration;
class CreateEmployeesRecordView extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
\DB::statement("
CREATE VIEW employees_records
AS
SELECT
employees.emp_no,
employees.first_name,
employees.last_name,
employees.gender,
employees.hire_date,
employees.birth_date,
dept_emp.dept_no,
departments.dept_name,
mananger.emp_no AS manager_emp_no,
mananger.first_name AS manager_first_name,
mananger.last_name AS manager_last_name
FROM
employees
LEFT JOIN dept_emp ON employees.emp_no = dept_emp.emp_no
LEFT JOIN departments ON dept_emp.dept_no = departments.dept_no
LEFT JOIN dept_manager ON departments.dept_no = dept_manager.dept_no
LEFT JOIN employees mananger ON dept_manager.emp_no = mananger.emp_no;
");
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
}
}
# Run the migration
php artisan migrate
Managing it via Console Command
php artisan make:command CreateOrReplaceEmployeeRecordsViewCommand
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CreateOrReplaceEmployeeRecordsViewCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'view:CreateOrReplaceEmployeeRecordsView';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Create or Replace SQL View.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
\DB::statement("
CREATE OR REPLACE VIEW employees_records
AS
SELECT
employees.emp_no,
employees.first_name,
employees.last_name,
employees.gender,
employees.hire_date,
employees.birth_date,
dept_emp.dept_no,
departments.dept_name,
mananger.emp_no AS manager_emp_no,
mananger.first_name AS manager_first_name,
mananger.last_name AS manager_last_name
FROM
employees
LEFT JOIN dept_emp ON employees.emp_no = dept_emp.emp_no
LEFT JOIN departments ON dept_emp.dept_no = departments.dept_no
LEFT JOIN dept_manager ON departments.dept_no = dept_manager.dept_no
LEFT JOIN employees mananger ON dept_manager.emp_no = mananger.emp_no;
");
}
}
Using Model To View
# Create a new model
php artisan make:model EmployeesRecord
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class EmployeesRecord extends Model
{
}
Test out the newly created Model
# For this we will be using tinker
php artisan tinker
>>> $e = \App\EmployeesRecord::first();
=> App\EmployeesRecord {#2885
emp_no: 10001,
first_name: "Georgi",
last_name: "Facello",
gender: "M",
hire_date: "1986-06-26",
birth_date: "1953-09-02",
dept_no: "d005",
dept_name: "Development",
manager_emp_no: 110511,
manager_first_name: "DeForest",
manager_last_name: "Hagimont",
}
>>> $e = \App\EmployeesRecord::where('emp_no', 10003)->first();
=> App\EmployeesRecord {#2896
emp_no: 10003,
first_name: "Parto",
last_name: "Bamford",
gender: "M",
hire_date: "1986-08-28",
birth_date: "1959-12-03",
dept_no: "d004",
dept_name: "Production",
manager_emp_no: 110303,
manager_first_name: "Krassimir",
manager_last_name: "Wegerle",
}
Ref - http://blog.tekz.io/laravel-eloquent-how-to-effectively-manage-sql-views/
To achieve this there is a good article here
I will show some code from the article .
Alter a base class like following:
public function save(array $options = [])
{
$this->toWriteMode();
try {
$saved = parent::save($options);
} catch (\Exception $e) {
$this->toReadMode();
throw $e;
}
$this->toReadMode();
return $saved;
}
protected $readOnly = [];
protected $readOnlyCache = [];
public function save(array $options = [])
{
$this->toWriteMode();
$this->cacheReadOnly();
try {
$saved = parent::save($options);
} catch (\Exception $e) {
$this->toReadMode();
throw $e;
}
$this->toReadMode();
$this->restoreReadOnly();
return $saved;
}
protected function cacheReadOnly()
{
$this->readOnlyCache = [];
foreach ($this->readOnly as $key) {
$value = $this->getAttributeValue($key);
$this->readOnlyCache[$key] = $value;
$this->__unset($key);
}
}
protected function restoreReadOnly()
{
foreach ($this->readOnlyCache as $key => $value) {
$this->setAttribute($key, $value);
}
}
Create Employee model as follows:
class Employee extends BaseModel
{
protected $table = 'employees';
protected $fillable = ['name'];
protected $guarded = ['id'];
public function people()
{
return $this->hasMany('Person');
}
}
Create EagerEmployee class as follows:
class EagerEmployee extends Employee
{
protected $readFrom = 'employeeView'; //Use your view name
protected $readOnly = ['person_ids'];
public function getPersonIdsAttribute($ids)
{
return $this->intArrayAttribute($ids);
}
}
This class will read its data from the view and we can save and retrieve it as normal. It will fetch read only attributes and they will be handled appropriately when saving.
That new intArrayAttribute() method just converts the comma delimited id string returned from the view into an array of integers.
We can use the Employee internally but if we need those extra read only attributes, say in an api response, we can use the EagerEmployee class.
P.S. The above code is copied from the given article and changed according to your needs.
Update:
Since old link to article is broken I'm adding a link to cached page of the site.
New Link to Article
Old Link to Article
'options' => [
\PDO::ATTR_EMULATE_PREPARES => true
]
Add Code to "config/database.php"
see picture below
Show Example

Getting the last User ID in Zend Framework

Using MySQL query browser, I manually made a table called users and input some date in the fields. I set the primary key to id and set it to auto increment. There are 3 rows, the highest id is 3.
I then made the following class in the method directory to call upon the data in the table etc.
class Application_Model_DbTable_User extends Zend_Db_Table_Abstract
{
protected $_name = 'user';
public function getLatestUserId()
{
$id = $this->getAdapter()->lastInsertId();
return $id;
}
}
In the controller I do the following which gets the value generated by the method and lets the view access it:
$usersDbModel = new Application_Model_DbTable_User();
$lastUserId = $usersDbModel->getLatestUserId();
$this->view->lastUserId = $lastUserId;
In the view I then echo it to display it to the user:
echo $this->lastUserId;
However, even though my last id in the users table is 3. It displays 0.
I have also tried:
public function getLatestUserId()
{
$sql = 'SELECT max(id) FROM user';
$query = $this->query($sql);
$result = $query->fetchAll();
return $result;
}
But this just throws out a server error.
What have I done wrong?
Am I missing something?
Is there another way of doing this?
The answer was:
$sql = 'SELECT max(id) FROM user';
$query = $this->getAdapter()->query($sql);
$result = $query->fetchAll();
return $result[0]['max(id)'];
If you queried like "SELECT id FROM USERS SORT BY id DESC LIMIT 0,1"
You would get nothing but the id of the newest user, no?
if you use a select statement like
SELECT max(id) FROM USERS;
If you haven't tried having a function in the controller try something like this.
class IndexController extends Zend_Controller_Action {
public function init() {
}
public function indexAction() {
}
public function getLatestUserId()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();
$sqlrequest = "select max(id) as Idmax from user";
$rows = $db->fetchAll($sqlrequest);
foreach ($rows as $row)
echo $maxId = $row['Idmax'];
return $maxId;
}
}
and your bootstrap file would look something like
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initConfig()
{
$config = new Zend_Config($this->getOptions());
Zend_Registry::set('config', $config);
return $config;
}
}
Hopefully something like that works, hope it helped
The problem is that Mysql doesn't really support lastInsertId() it will in some cases return the last id of an auto incrementing primary key.
Several solutions have been presented here and most will return the last id of the primary key, which may or may not be what you really need.
This method will also do the same using the select() object.
public function getlastInsertId(){
$select = $this->select();
$select->from($this->_name, "id");
$select->order('id DESC');
$select->limit(0, 1);
$result = $this->fetchAll($select)->current();
return $result->id;
}
I think that over time you may find these kinds of methods unreliable if what you're really after is the last id you inserted. Over time as records are added and deleted the database may or may not fill in vacant id's depending on which database you are currently using and how that database is set up.
In most cases we need the id of the last item inserted very soon after inserting it, usually to update a view script. In this instance I usually just make the whole row object part of the return.
Here is an example of what I mean:
/**this method will save or update a record depending on data present in the array*/
public function saveUser(array $data) {
/**cast data array as std object for convience*/
$dataObject = (object) $data;
/**if id exists as array and has a non null value*/
if (array_key_exists('id', $data) && isset($data['id'])) {
/**find row if updating*/
$row = $this->find($dataObject->id)->current();
} else {
/**create new row*/
$row = $this->createRow();
}
$row->first_name = $dataObject->first_name;
$row->last_name = $dataObject->last_name;
$row->email = $dataObject->email;
/**save or update row*/
$row->save();
/**return the $row you just built or you can return $result = $row->save(); and get*/
/** just the primary key. Save() will throw an exception if table is marked read only*/
return $row;
}