Zend Framework v1 INSERT INTO multiple rows - mysql

Im working on E-Shops based on Zend Framework v1.12 and I need to create a parser of product list with thousands of records. I'd tried to make a loop of createRow() -> save() but I found it too slow with big lists.
Does Zend fr. have an functional to save multiply record in one query?

No, Zend Framework v1 doesn't have such functional. But it's not so hard to make an implementation of INSERT INTO for your needs. Here is my function:
/**
* #brief Safe implementation of INSERT INTO
*
* #param [in] $array Array[] of values 'column'=>'value"
* #return void
*
*/
protected function saveRows($array) {
$values=$columns = array();
$vLabels=$cLables = '';
foreach ($array as $colval) {
$vLabels.="(";
foreach ($colval as $column=>$value) {
if (!$ready) {
array_push($columns,$column);
$cLables.='?,';
}
array_push($values,$value);
$vLabels.='?,';
}
$vLabels = rtrim($vLabels,', ');
!$ready ? $cLables = rtrim($cLables,', ') : null;
$vLabels .= "),";
$ready = true;
}
$vLabels = rtrim($vLabels,', ');
$query="INSERT INTO `".$this->primary_key."` (".$cLables.") VALUES ".$vLabels;
$subst=array_merge($columns,$values);
$this->query($query,$subst);
}

Related

Laravel Eloquent (QueryBuilder) filtering in hasMany relations tables

Have this code:
this is in RentRequest model:
/**
* Apply all relevant advert filters.
*
* #param Builder $query
* #param ParameterFilter $filters
* #return Builder
*/
public function scopeParamFilter($query, ParameterFilter $filters)
{
$query->leftJoin('request_parameter', 'rent_requests.id', '=', 'request_parameter.request_id');
return $filters->apply($query);
}
this in parameter filter:
/**
* Filter the query by a given area.
*
* #param $total_area
* #return \Illuminate\Database\Eloquent\Builder
*/
protected function total_space($total_area)
{
$this->builder->where(function ($queryId) use ($total_area) {
$query = DB::table('request_parameter')->where('request_parameter.key', 'total_space_from');
if (!empty($total_area['from'])) {
$query->where('request_parameter.value', '>=', (int) $total_area['from']);
}
$valueIds = $query->pluck('request_id');
$haveNoValueIds = DB::table('request_parameter')
->selectRaw('DISTINCT request_id')
->whereNotIn('request_id',
DB::table('request_parameter')
->select('request_id')
->where('key', 'total_space')
)
->pluck('request_id');
$advertIds = $valueIds->merge($haveNoValueIds);
$queryId->whereIn('request_parameter.request_id', $advertIds->all());
});
return $this->builder;
}
this is request_parameter schema:
so i have simple has many relation with parameters table based on rent_request.id
now i make filter logic, and try to do the same logic as previous developers made, but i cant understand it
main question is how to filter requests by the parameters that lying in the another table ?
current filter function works with the same logic in another project, maybe there are errors there ?
sorry for my english <3
this is final version of my function, it works for me
/**
* Filter the query by a given area.
*
* #param $total_area
* #return \Illuminate\Database\Eloquent\Builder
*/
protected function total_space($total_area)
{
$this->builder->where(function ($queryId) use ($total_area) {
$query = DB::table('request_parameter');
if (!empty($total_area['from'])) {
$query->where('request_parameter.key', 'total_space_from')
->where('request_parameter.value', '<=', (int) $total_area['from']);
}
if (!empty($total_area['to'])) {
$query->where('request_parameter.key', 'total_space_to')
->where('request_parameter.value', '<=', (int) $total_area['to']);
}
$valueIds = $query->pluck('request_id');
info($valueIds);
$haveNoValueIds = DB::table('request_parameter')
->selectRaw('DISTINCT request_id')
->whereNotIn('request_id',
DB::table('request_parameter')
->select('request_id')
->where('key', 'total_space_from')
->orWhere('key', 'total_space_to')
)
->pluck('request_id');
$advertIds = $valueIds->merge($haveNoValueIds);
$queryId->whereIn('request_parameter.request_id', $advertIds->all());
});
return $this->builder;
}
p.s. the filter algo is next: even when adverts dont have these parameters, its also return from filter function.
these was the key to understand what they are do in this function, and helps me to solve my problem.

How to use triggers in laravel?

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;
});
}

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';

Doctrine - delete all entities

I have problem with deleting all rows in database. I can't find out how to do it. I'm using Symfony and Doctrine. Somewhere I read, that it isn't possible "normal" way, but I can do it by DQL (createQuery), but I don't know syntax.
public function resetDatabase(EntityManagerInterface $em)
{
$query = $em->createQuery('DELETE ???');
$query->execute();
return new Response('', Response::HTTP_OK);
}
public function resetDatabase(EntityManagerInterface $em)
{
$query = $em->createQuery(
'DELETE FROM App\Entity\YourEntity e WHERE e.age > :ageparameter'
)->setParameter('ageparameter', 10)->execute();
return new Response('', Response::HTTP_OK);
}
Ou... I have find out, how to do it.
/**
* #Route("/resetdatabase")
*/
public function resetDatabase(EntityManagerInterface $em)
{
$repository = $em->getRepository(MoneyDatabase::class);
$entities = $repository->findAll();
foreach ($entities as $entity) {
$em->remove($entity);
}
$em->flush();
return new Response('', Response::HTTP_OK);
}
But sometimes it must run twice, because somehow after 30 seconds entities return (but there are only compulsory columns, others are null). And after second run it disappear completely. It's strange, that it does only sometimes. Why it does at all?

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;
}