Laravel Bulk UPDATE - laravel

I'm trying to update a table containing a slug value with random slugs for each record.
$vouchers = Voucher->get(); // assume 10K for example
foreach ($vouchers as $voucher) {
$q .= "UPDATE vouchers set slug = '" . Str::random(32) . "' WHERE id = " . $voucher->id . ";";
}
DB::statement($q);
There are about 2 million records so I need to perform this as a bulk. Doing it as separate records is taking way too long. I can't seem to find a way to bulk run them, say in groups of 10K or something.
Tried a bunch of variations of ->update() and DB::statement but can't seem to get it to go.

In case someone land in this page like me, laravel allows a bulk update as:
$affectedRows = Voucher::where('id', '=', $voucher->id)->update(array('slug' => Str::random(32)));
See "Updating A Retrieved Model" under http://laravel.com/docs/4.2/eloquent#insert-update-delete

I have created My Custom function for Multiple Update like update_batch in CodeIgniter.
Just place this function in any of your model or you can create helper class and place this function in that class:
//test data
/*
$multipleData = array(
array(
'title' => 'My title' ,
'name' => 'My Name 2' ,
'date' => 'My date 2'
),
array(
'title' => 'Another title' ,
'name' => 'Another Name 2' ,
'date' => 'Another date 2'
)
)
*/
/*
* ----------------------------------
* update batch
* ----------------------------------
*
* multiple update in one query
*
* tablename( required | string )
* multipleData ( required | array of array )
*/
static function updateBatch($tableName = "", $multipleData = array()){
if( $tableName && !empty($multipleData) ) {
// column or fields to update
$updateColumn = array_keys($multipleData[0]);
$referenceColumn = $updateColumn[0]; //e.g id
unset($updateColumn[0]);
$whereIn = "";
$q = "UPDATE ".$tableName." SET ";
foreach ( $updateColumn as $uColumn ) {
$q .= $uColumn." = CASE ";
foreach( $multipleData as $data ) {
$q .= "WHEN ".$referenceColumn." = ".$data[$referenceColumn]." THEN '".$data[$uColumn]."' ";
}
$q .= "ELSE ".$uColumn." END, ";
}
foreach( $multipleData as $data ) {
$whereIn .= "'".$data[$referenceColumn]."', ";
}
$q = rtrim($q, ", ")." WHERE ".$referenceColumn." IN (". rtrim($whereIn, ', ').")";
// Update
return DB::update(DB::raw($q));
} else {
return false;
}
}
It will Produces:
UPDATE `mytable` SET `name` = CASE
WHEN `title` = 'My title' THEN 'My Name 2'
WHEN `title` = 'Another title' THEN 'Another Name 2'
ELSE `name` END,
`date` = CASE
WHEN `title` = 'My title' THEN 'My date 2'
WHEN `title` = 'Another title' THEN 'Another date 2'
ELSE `date` END
WHERE `title` IN ('My title','Another title')

Chunking results is the best way to do this kind of stuff without eating all of your RAM and Laravel support chunking results out of the box.
For example:
Voucher::chunk(2000, function($vouchers)
{
foreach ($vouchers as $voucher)
{
//
}
});

I made a bulk update function to use in my Laravel projects. It may be useful for anyone who wants to use the batch update query in Laravel. Its first parameter is the table name string, second is the key name string based on which you want to update the row or rows and most of the times it will be the 'id' and the third parameter is a data array in the following format:
array(
array(
'id' => 1,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
array(
'id' => 2,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
//...
);
The function will return the number of affected rows. Function definition:
private function custom_batch_update(string $table_name = '', string $key = '', Array $update_arr = array()) {
if(!$table_name || !$key || !$update_arr){
return false;
}
$update_keys = array_keys($update_arr[0]);
$update_keys_count = count($update_keys);
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} = $key_name . ' = CASE';
}
$length = count($update_arr);
$index = 0;
$query_str = 'UPDATE ' . $table_name . ' SET ';
$when_str = '';
$where_str = ' WHERE ' . $key . ' IN(';
while ($index < $length) {
$when_str = " WHEN $key = '{$update_arr[$index][$key]}' THEN";
$where_str .= "'{$update_arr[$index][$key]}',";
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= $when_str . " '{$update_arr[$index][$key_name]}'";
}
$index++;
}
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= ' ELSE ' . $key_name . ' END, ';
$query_str .= $when_{$key_name};
}
$query_str = rtrim($query_str, ', ');
$where_str = rtrim($where_str, ',') . ')';
$query_str .= $where_str;
$affected = DB::update($query_str);
return $affected;
}
It will produce and execute the query string like this:
UPDATE table_name SET col_1_name = CASE
WHEN id = '1' THEN 'col_1_value'
WHEN id = '2' THEN 'col_1_value'
ELSE col_1_name END,
col_2_name = CASE
WHEN id = '1' THEN 'col_2_value'
WHEN id = '2' THEN 'col_2_value'
ELSE col_2_name END
WHERE id IN('1','2')

Related

How to exec store procedure with many parameter to restAPI in Laravel 6

I have 2 apps, 1 is front and and the other 1 is webapi server.
In webapi, i have to exec a Store Procedure on mssql server. That SP has 52 input parameters.
I want to call that SP in My API Controller.
My question is how to pass those 52 parameter from my Front end to my API server.
I'm successfully testing with static parameter in Postman.
The frontend is Laravel 5.8 and my API server is Laravel 6.2
Here's my API controller, still with static parameters that I want to get as an array '$allmyparams' (if possible) from my Frontend
public function as_add_reg($allmyparams)
{
//these are static params for testing purpose
$param1 = "ID02007160013";
$param2 = "2020-07-17 00:00:00";
$param3 = "00-00-77-32";
$param4 = '00128';
$param5 = '02 ';
$param6 = '11:27';
$param7 = '06 ';
$param8 = ' ';
$param9 = 'DESY ARIANA';
$param10 = '';
$param11 = 'RAYA KRONJO ';
$param12 = 'TANGERANG';
$param13 = ' ';
$param14 = ' ';
$param15 = ' ';
$param16 = ' ';
$param17 = ' ';
$param18 = 'TANGERANG ';
$param19 = '002 ';
$param20 = 'P';
$param21 = ' ';
$param22 = '1978-02-03 00:00:00';
$param23 = 'none ';
$param24 = ' ';
$param25 = '00002 ';
$param26 = '$0.0000';
$param27 = ' ';
$param28 = ' ';
$param29 = 'none ';
$param30 = 0;
$param31 = 42;
$param32 = 5;
$param33 = 13;
$param34 = '2020-07-16 11:28:44.920';
$param35 = 'mssql';
$param36 = 0;
$param37 = ' ';
$param38 = ' ';
$param39 = '2020-07-16 00:00:00';
$param40 = 'none ';
$param41 = '';
$param42 = '';
$param43 = ' ';
$param44 = 'none ';
$param45 = '';
$param46 = '';
$param47 = 'none ';
$param48 = 'none ';
$param49 = 'none ';
$param50 = 0;
$param51 = 0;
$param52 = '1';
$referral_registers = DB::connection('as_api')
->select('EXEC reg_Insert ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?',
array($param1, $param2, $param3, $param4, $param5, $param6, $param7, $param8, $param9, $param10,
$param11, $param12, $param13, $param14, $param15, $param16, $param17, $param18, $param19, $param20,
$param21, $param22, $param23, $param24, $param25, $param26, $param27, $param28, $param29, $param30,
$param31, $param32, $param33, $param34, $param35, $param36, $param37, $param38, $param39, $param40,
$param41, $param42, $param43, $param44, $param45, $param46, $param47, $param48, $param49, $param50,
$param51, $param52));
return response()->json([
'success' => true,
'data' => $referral_registers
]);
}
And In the frontend, here's the function that calls that webAPI server
$allmyparam=arrray(
"param1"=>1',
"param2"=>"example",
...
"param52"=>"example",
);
$response2 = $client->get($webapi_url . '/api/heru/as_add_reg/' . $allmyparams, [
'cookies' => $cookieJar,
'headers' => [
'Authorization' => 'Bearer ' . $webapi_token,
'Accept' => 'application/json',
],
]);
Without arguing the solution you share, here.
i think you are looking for:
public function controller_method(Request $request) {
$request->all();
}
See: https://laravel.com/docs/7.x/requests
To get a more detailed explanation on how to handle request input
Or.. if you are having a flat array with only values, and want to get it as as array with key and values
You could use collection helpers of laravel mapWithKeys
See: https://laravel.com/docs/7.x/collections#method-mapwithkeys
Based on your comment, i guess you don't get what i mean..
$param1 = "ID02007160013";
$param2 = "2020-07-17 00:00:00";
$param3 = "00-00-77-32";
// ... and so on
//could be done as
$params[] = "val1"
$params[] = "val2"
// Then for example you can access it as an array
//Just like accessing $params
//If you need it as separate values, on a function argument, you could use //the spread operator like
...$params
See: https://laravel-news.com/spread-operator-in-array-expressions-coming-to-php-7-4
For some examples.. (and only works if you have a recent PHP version)
Then if you want it to convert to a an associative array
foreach ($params as $index => $param) {
$newArray["param${index}"] = $param;
}
You could also use the https://laravel.com/docs/7.x/collections
helper methods for these, but guess, these are harder to understand for you for now.
.. Sending it as query parameter
$client->request('GET', 'http://httpbin.org', [
'query' => ['foo' => 'bar']
]);
See: http://docs.guzzlephp.org/en/stable/quickstart.html#query-string-parameters
If you insist having it as an string you could also use the native php function: https://www.php.net/manual/en/function.http-build-query.php

How to pass variable $data to controller?

I've no idea to pass $data variable from Model to Controller.
In Model:
function active(){
$query = $this->db->query(" SELECT * FROM `event` WHERE DATE_FORMAT( NOW( ) , '%m-%d-%Y' ) BETWEEN START AND END ");
foreach($query->result_array() as $row){
$ev_name = $row['ev_name'];
$image = $row['ev_image'];
$start = $row['start'];
$end = $row['end'];
$desc = $row['ev_dec'];
$ev_id = $row['ev_id'];
}
$data = array('ev_name' => $ev_name,
'ev_image' => $image,
'start' => $start,
'end' => $end,
'ev_desc' =>$desc,
'ev_id'=> $ev_id
);
echo $data;
}
In Controller:
function active_event()
{
$this->load->view('active_event');
$this->load->model('Usermodel', Sdata);
}
You should use return keyword which is used for passing data from one function to another. You also need to load and call model method before loading view so that you can use data from modal in view. I think you need to check MVC pattern and Codeigniter userguide.
In your model,
function active(){
$query = $this->db->query(" SELECT * FROM `event` WHERE DATE_FORMAT( NOW( ) , '%m-%d-%Y' ) BETWEEN START AND END ");
foreach($query->result_array() as $row){
$ev_name = $row['ev_name'];
$image = $row['ev_image'];
$start = $row['start'];
$end = $row['end'];
$desc = $row['ev_dec'];
$ev_id = $row['ev_id'];
}
$data = array('ev_name' => $ev_name,
'ev_image' => $image,
'start' => $start,
'end' => $end,
'ev_desc' =>$desc,
'ev_id'=> $ev_id
);
return $data;
}
In your controller,
function active_event()
{
$this->load->model('YOUR MODEL NAME');
$data = $this->YOURMODELNAME->active();
$this->load->view('active_event', $data);
}

Yii: save multiple records in one query

I'm trying to save a lot of CActiveRecord model objects in a loop.
I have something like this:
foreach ($array_of_items as $item) {
$values = array(
"title" => $item->title,
"content" => $item->content,
);
$object = new MyModel;
$object->attributes = $values;
$object->save();
}
In my case, this creates about 400 CActiveRecord objects. The saving process is really slow, because each save() queries the database.
Is there a way to save all those objects in one go?
Something like:
$objects = array();
foreach ($array_of_items as $item) {
$values = array(
"title" => $item->title,
"content" => $item->content,
);
$object = new MyModel;
$object->attributes = $values;
$objects[] = $object;
}
save_all_objects($objects);
I could not find anything on the subject. Anyone?
you can validate() your model, and if it was ok you can append it so a sql text for insert,
and after your loop, just use databases commandBuilder() and execute your prepared text
$sql = '';
if($object->validate())
{
$sql .= ',("' . $object->attr1 . '")'// append to script,(you get the idea, you need to also make a correct values)
}
...
if(!empty($sql))
{
$sql = 'INSERT INTO table (attr1) Values' . $sql;// make complete script
// execute that command
}
Since v1.1.14, the method createMultipleInsertCommand() of CDbCommandBuilder class is available.
For insert multi rows, Put this code in components folder under GeneralRepository.php file name.
<?php
class GeneralRepository
{
/**
* Creates and executes an INSERT SQL statement for several rows.
* By: Nabi K.A.Z. <www.nabi.ir>
* Version: 0.1.0
* License: BSD3
*
* Usage:
* $rows = array(
* array('id' => 1, 'name' => 'John'),
* array('id' => 2, 'name' => 'Mark')
* );
* GeneralRepository::insertSeveral(User::model()->tableName(), $rows);
*
* #param string $table the table that new rows will be inserted into.
* #param array $array_columns the array of column datas array(array(name=>value,...),...) to be inserted into the table.
* #return integer number of rows affected by the execution.
*/
public static function insertSeveral($table, $array_columns)
{
$connection = Yii::app()->db;
$sql = '';
$params = array();
$i = 0;
foreach ($array_columns as $columns) {
$names = array();
$placeholders = array();
foreach ($columns as $name => $value) {
if (!$i) {
$names[] = $connection->quoteColumnName($name);
}
if ($value instanceof CDbExpression) {
$placeholders[] = $value->expression;
foreach ($value->params as $n => $v)
$params[$n] = $v;
} else {
$placeholders[] = ':' . $name . $i;
$params[':' . $name . $i] = $value;
}
}
if (!$i) {
$sql = 'INSERT INTO ' . $connection->quoteTableName($table)
. ' (' . implode(', ', $names) . ') VALUES ('
. implode(', ', $placeholders) . ')';
} else {
$sql .= ',(' . implode(', ', $placeholders) . ')';
}
$i++;
}
$command = Yii::app()->db->createCommand($sql);
return $command->execute($params);
}
}
And usage anywhere:
$rows = array(
array('id' => 1, 'name' => 'John'),
array('id' => 2, 'name' => 'Mark')
);
GeneralRepository::insertSeveral(User::model()->tableName(), $rows);
https://www.yiiframework.com/extension/yii-insert-multi-rows

Magento: improving default search engine

So, I changed the default Magento search engine slightly, and it works close to how I want it. (i.e. OR term search to AND). However, there is one more thing that I'd like to implement. When a person searches for a series of terms, like Green Apple A, I'd like the product Green Apple A to show up first. Right now, with the AND operator, the results are in the order they were pulled from the DB. So, the Green Apple A might show up in anywhere.
Here is the function that prepares the results.. It is a bit complicated for me, and I'm wondering if there's an easy way to "append" a search result that looks for the specific sequence of the inputted terms and concatenates the results, giving this priority, so it shows up first.
(Sorry for the long code. I typically don't like posting large amount of code)
From Fulltext.php in /stores/my_website/app/code/local/Mage/CatalogSearch/Model/Resource
public function prepareResult($object, $queryText, $query)
{
$adapter = $this->_getWriteAdapter();
if (!$query->getIsProcessed()) {
$searchType = $object->getSearchType($query->getStoreId());
$preparedTerms = Mage::getResourceHelper('catalogsearch')
->prepareTerms($queryText, $query->getMaxQueryWords());
$bind = array();
$like = array();
$likeCond = '';
if ($searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_LIKE
|| $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE
) {
$helper = Mage::getResourceHelper('core');
$words = Mage::helper('core/string')->splitWords($queryText, true, $query->getMaxQueryWords());
foreach ($words as $word) {
$like[] = $helper->getCILike('s.data_index', $word, array('position' => 'any'));
}
if ($like) {
$likeCond = '(' . join(' AND ', $like) . ')';
}
}
$mainTableAlias = 's';
$fields = array(
'query_id' => new Zend_Db_Expr($query->getId()),
'product_id',
);
$select = $adapter->select()
->from(array($mainTableAlias => $this->getMainTable()), $fields)
->joinInner(array('e' => $this->getTable('catalog/product')),
'e.entity_id = s.product_id',
array())
->where($mainTableAlias.'.store_id = ?', (int)$query->getStoreId());
if ($searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_FULLTEXT
|| $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE
) {
$bind[':query'] = implode(' ', $preparedTerms[0]);
$where = Mage::getResourceHelper('catalogsearch')
->chooseFulltext($this->getMainTable(), $mainTableAlias, $select);
}
if ($likeCond != '' && $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE) {
$where .= ($where ? ' AND ' : '') . $likeCond;
} elseif ($likeCond != '' && $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_LIKE) {
$select->columns(array('relevance' => new Zend_Db_Expr(0)));
$where = $likeCond;
}
if ($where != '') {
$select->where($where);
}
$sql = $adapter->insertFromSelect($select,
$this->getTable('catalogsearch/result'),
array(),
Varien_Db_Adapter_Interface::INSERT_ON_DUPLICATE);
$adapter->query($sql, $bind);
$query->setIsProcessed(1);
}
return $this;
}
I think you can try this free extension for default search
http://www.magentocommerce.com/magento-connect/catalog/product/view/id/12202/s/enhanced-default-search-9697

Lof K2Scroller Module

I have been using K2 Scroller module developed by Land of Coder. When I use this module to display same category items in the items view the module displays items in the ascending order of the date created and it is the default and only setting available in the module parameter settings in the back-end. However, I want the module to display the items in date wise descending order. So I chose to edit the default code in the helper which I suppose is used to process items based on the back-end settings. And this is the part of the code in the helper file which I think controls the order:
public function __getList( $params ){
global $mainframe;
/*some irrelevant code removed*/
$condition = $this->buildConditionQuery( $params );
$limitDescriptionBy = $params->get('limit_description_by','char');
$ordering = $params->get( 'k2_ordering', 'created_desc');
$limit = $params->get( 'limit_items', 5 );
$ordering = str_replace( '_', ' ', $ordering );
$my = &JFactory::getUser();
$aid = $my->get( 'aid', 0 );
/*some irrelevant code removed*/
$extraURL = $params->get('open_target')!='modalbox'?'':'&tmpl=component';
$excludeIds = $params->get('exclude_ids', '');
$db = &JFactory::getDBO();
$date =& JFactory::getDate();
$now = $date->toMySQL();
$dateFormat = $params->get('date_format', 'DATE_FORMAT_LC3');
$limitDescriptionBy = $params->get('limit_description_by','char');
$isAuthor= $params->get('itemAuthor',0);
require_once ( JPath::clean(JPATH_SITE.'/components/com_k2/helpers/route.php') );
$query = "SELECT a.*, cr.rating_sum/cr.rating_count as rating, c.name as categoryname,
c.id as categoryid, c.alias as categoryalias, c.params as categoryparams, cc.commentcount as commentcount".
" FROM #__k2_items as a".
" LEFT JOIN #__k2_categories c ON c.id = a.catid" .
" LEFT JOIN #__k2_rating as cr ON a.id = cr.itemid".
" LEFT JOIN (select cm.itemid as id, count(cm.id) as commentcount from #__k2_comments as cm
where cm.published=1 group by cm.itemid) as cc on a.id = cc.id";
$query .= " WHERE a.published = 1"
. " AND a.access get('featured_items_show','0') == 0 ){
$query.= " AND a.featured != 1";
} elseif( $params->get('featured_items_show','0') == 2 ) {
$query.= " AND a.featured = 1";
}
if( trim($excludeIds) ){
$query .= " AND a.id NOT IN(".$excludeIds.") ";
}
$query .= $condition . ' ORDER BY ' . $ordering;
$query .= $limit ? ' LIMIT ' . $limit : '';
$db->setQuery($query);
$data = $db->loadObjectlist();
/*some irrelevant code removed*/
return $data;
}
/**
* build condition query base parameter
*
* #param JParameter $params;
* #return string.
*/
public function buildConditionQuery( $params ){
$source = trim($params->get( 'k2_source', 'k2_category' ) );
if( $source == 'k2_category' ){
$catids = $params->get( 'k2_category','');
if( !$catids ){
return '';
}
$catids = !is_array($catids) ? $catids : '"'.implode('","',$catids).'"';
$condition = ' AND a.catid IN( '.$catids.' )';
} else {
$ids = preg_split('/,/',$params->get( 'k2_items_ids',''));
$tmp = array();
foreach( $ids as $id ){
$tmp[] = (int) trim($id);
}
$condition = " AND a.id IN('". implode( "','", $tmp ) ."')";
}
return $condition;
}
Am I editing the right part of the code or am I missing something else.
I am looking forward to your help
Thanks.
Maybe the best way would be to modify the xml file of the module.
I looked at the code of Lof K2Scroller (v 2.2 for Joomla 2.5) and the different ordering options are there.
However if you want to modify the default option, you are in the right file, just replace 'created_desc' for 'created_asc' .

Resources