Optimize foreach loop in laravel - laravel

I need bulk insert in subscriber table and subscriber field table in which data comes from CSV file.
The subscriber table need the only email and subscriber fields table need subscriber id from subscriber table, field id from field table and other CSV fields.
So, I write this code for this job and here a lot of foreach loop, that's why it takes a lot of time for execute when I insert a large CSV file.
Now, Any possible to optimize this code?
Here is my code :
$emails = array();
foreach ($data as $item) {
array_push($emails, $item['email']);
}
$subscribers = Subscriber::select('email')->whereIn('email', $emails)->where('mail_list_id', $this->id)->get();
//check exists mail in database
$exists_mail = array();
foreach ($subscribers as $item) {
$exists_mail[$item->email] = true;
}
//get subscriber unique key
$subscriber_uid = array();
//get all field value
$total_field = array();
//bulk insert in subscribers table
$subscriberBatch = array();
foreach ($data as $item) {
if (!isset($exists_mail[$item['email']])) {
$column['uid'] = uniqid();
$column['mail_list_id'] = $this->id;
$column['email'] = $item['email'];
$column['status'] = Subscriber::STATUS_SUBSCRIBED;
$column['subscription_type'] = Subscriber::SUBSCRIPTION_TYPE_IMPORTED;
array_push($subscriberBatch, $column);
array_push($subscriber_uid, $column['uid']);
$fieldKey['uid'] = $column['uid'];
foreach ($fields as $field) {
$fieldKey[Str::lower($field['tag'])] = $item[Str::lower($field['tag'])];
}
array_push($total_field, $fieldKey);
}
}
Subscriber::insert($subscriberBatch);
//bulk insert in subscriber fields table
$totalSubscriber = Subscriber::select('id')->whereIn('uid', $subscriber_uid)->get()->toArray();
foreach ($totalSubscriber as $index => $subscriber) {
$total_field[$index]['subscriber_id'] = $subscriber['id'];
}
$fieldBatch = array();
foreach ($total_field as $item) {
foreach ($fields as $field) {
$fieldColumn['subscriber_id'] = $item['subscriber_id'];
$fieldColumn['field_id'] = $field['id'];
$fieldColumn['value'] = $item[Str::lower($field['tag'])];
array_push($fieldBatch, $fieldColumn);
}
}
SubscriberField::insert($fieldBatch);

//set all email in a array
$emails = array();
foreach ($data as $item) {
array_push($emails, $item['email']);
}
$exists_mail = array();
$subscribers = Subscriber::whereIn('email', $emails)
->where('mail_list_id', $this->id)
->pluck('email')
->toArray();
//get subscriber unique key
$subscriber_uid = array();
//get all field value
$total_field = array();
//bulk insert in subscribers table
$subscriberBatch = array();
foreach ($data as $item) {
if(!in_array($item['email'], $subscribers)){
$column['uid'] = uniqid();
$column['mail_list_id'] = $this->id;
$column['email'] = $item['email'];
$column['status'] = Subscriber::STATUS_SUBSCRIBED;
$column['subscription_type'] = Subscriber::SUBSCRIPTION_TYPE_IMPORTED;
array_push($subscriberBatch, $column);
array_push($subscriber_uid, $column['uid']);
$fieldKey['uid'] = $column['uid'];
foreach ($fields as $field) {
$fieldKey[Str::lower($field['tag'])] = $item[Str::lower($field['tag'])];
}
array_push($total_field, $fieldKey);
}
}
Subscriber::insert($subscriberBatch);
//bulk insert in subscriber fields table
$totalSubscriber = Subscriber::select('id')
->whereIn('uid', $subscriber_uid)
->get()
->toArray();
$fieldBatch = array();
foreach ($totalSubscriber as $index => $subscriber) {
$total_field[$index]['subscriber_id'] = $subscriber['id'];
}
foreach ($total_field as $item) {
foreach ($fields as $field) {
$fieldColumn['subscriber_id'] = $item['subscriber_id'];
$fieldColumn['field_id'] = $field['id'];
$fieldColumn['value'] = $item[Str::lower($field['tag'])];
array_push($fieldBatch, $fieldColumn);
}
}
SubscriberField::insert($fieldBatch);
I remove below code and use pluck
$subscribers = Subscriber::select('email')->whereIn('email', $emails)->where('mail_list_id', $this->id)->get();
//check exists mail in database
$exists_mail = array();
foreach ($subscribers as $item) {
$exists_mail[$item->email] = true;
}
We more optimize and we can remove below code
foreach ($total_field as $item) {
foreach ($fields as $field) {
$fieldColumn['subscriber_id'] = $item['subscriber_id'];
$fieldColumn['field_id'] = $field['id'];
$fieldColumn['value'] = $item[Str::lower($field['tag'])];
array_push($fieldBatch, $fieldColumn);
}
}
Like:
//bulk insert in subscriber fields table
$totalSubscriber = Subscriber::select('id')
->whereIn('uid', $subscriber_uid)
->get()
->toArray();
$fieldBatch = array();
foreach ($totalSubscriber as $index => $subscriber) {
//$total_field[$index]['subscriber_id'] = $subscriber['id'];
foreach ($fields as $field) {
$fieldColumn['subscriber_id'] = $subscriber['id'];
$fieldColumn['field_id'] = $field['id'];
$fieldColumn['value'] = $item[Str::lower($field['tag'])];
array_push($fieldBatch, $fieldColumn);
}
}
But I don't know what type of data in $fields array if you provide field array the I will try more optimize.

Related

Requesting solution for laravel 8 project

I'm an elementary web developer, I'm facing a problem. Please help me solve this. I'm creating both row and column dynamic. for save() is fine. But for update, only name is updated and other item
quantities cannot. Here is my codes.
//for save()
public function stockAdd(Request $request)
{
$validator = validator(request()->all(), ['stock_name' => 'required']);
if($validator->fails()) {
return back()->withErrors($validator);
}
$user_id = Auth::user()->user_id;
$stock_id = random_int(100000, 999999);
$stocks = new Stocks();
$stocks->stock_id = $stock_id;
$stocks->owner_id = $user_id;
$stocks->stock_name = request()->stock_name;
$stocks->my_stock = 0;
$stocks->disable = 0;
$stocks->save();
$brands = Brands::all();
$products = Products::all();
foreach ($brands as $brand){
foreach ($products as $product){
if($product['brand_id'] == $brand['id']){
$product_id = $product->product_id;
$stockitems = new StockItems();
$stockitems->stock_id = $stock_id;
$stockitems->product_id = $product->product_id;
$stockitems->owner_id = $user_id;
if(request()->$product_id > 0){
$stockitems->count = request()->$product_id;
}else{
$stockitems->count = 0;
}
$stockitems->save();
}
}
}
return redirect()->back()->with('successAddMsg','Successfully Added');
}
//for update()
public function stockUpdate(Request $request, $id)
{
$validator = validator(request()->all(), ['stock_name' => 'required']);
if($validator->fails()) {
return back()->withErrors($validator);
}
$stock = Stocks::findOrFail($id);
$stock->stock_name = request()->stock_name;
$stock->my_stock = 0;
$stock->disable = 0;
$stock->update();
$brands = Brands::all();
$products = Products::all();
foreach ($brands as $brand){
foreach ($products as $product){
if($product['brand_id'] == $brand['id']){
$product_id = $product->product_id;
//dd($product_id);
$stockitemitems = DB::table("stock_items")->select("*")->where("owner_id",Auth::user()->user_id)->where("stock_id",$stock->stock_id)->get();
$stockitems->count = $request->input($product_id);
$stockitems->update();
}
}
}
return redirect(route('user.stock-list'))->with('successAddMsg','Successfully Added');
}
The problem shows like this "Creating default object from empty value"

How to skip blank rows in a csv file during import in Laravel

During the import of a CSV file, my import function creates a database record for every row of the import file. This means that if a user has left a blank row in the file then the import process creates a blank record in the database. How does one develop it so that the importer identifies blank/null rows in the CSV file, skips those blank/null rows, and only creates a record and imports a row if the row contains data?
Here is the Controller for the Import function:
public function process(Request $request)
{
$filename = $request->input('filename', false);
$path = storage_path('app/csv_import/'.$filename);
$hasHeader = $request->input('hasHeader', false);
$isAddingNewReligiousBackground = $request->input('is_adding_new_religious_background', false);
$fields = $request->input('fields', false);
$fields = array_flip(array_filter($fields));
$modelName = $request->input('modelName', false);
$model = 'App\\'.$modelName;
$reader = new SpreadsheetReader($path);
$insert = [];
$update = [];
$tags = [];
$team_id = $request->input('church_id');
$custom_fields = CustomField::where('created_by_team_id', $team_id)->get();
foreach ($reader as $key => $row) {
if ($hasHeader && $key == 0) {
continue;
}
$tmp = [];
$meta = [];
foreach ($fields as $header => $k) {
$tmp[$header] = $row[$k];
}
$tmp['created_by_id'] = auth()->user()->id;
$tmp['created_by_team_id'] = $team_id;
$tmp['created_at'] = now();
if ($modelName == 'Interest') {
$this->translateReligiousBackgroud($tmp, $isAddingNewReligiousBackground);
$meta = $this->processInterestMeta($tmp, $custom_fields);
$existing = Interest::matchingInterest((object) $tmp, $request->input('church_id'));
if ($existing) {
$update[] = $existing;
$tagsArr = array_filter((array) $request->input('interest_tags'));
foreach (\DB::table('interest_tag')->where('interest_id', $existing->id)->get() as $tag) {
$tagsArr[] = $tag->tag_id;
}
$existing->interest_tags()->sync(array_filter($tagsArr));
if (! empty($meta)) {
$existing->syncMeta($meta);
}
} else {
$tmp['meta'] = $meta;
$insert[] = $tmp;
}
} else {
$insert[] = $tmp;
}
}
$for_insert = array_chunk($insert, 10000); // this was 100, but the chunking was causing the system to only import the first 100 records, even though the success message said it imported all of them - LW 1/25/2019
foreach ($for_insert as $insert_item) {
if ($modelName == 'Interest') {
foreach ($insert_item as $item) {
$interest = new $model;
foreach ($item as $field => $value) {
if ($field != 'meta') {
$interest->$field = $value;
}
}
$interest->created_by_id = auth()->user()->id;
$interest->created_by_team_id = $request->input('church_id');
$interest->save();
// For some reason, created_by_team_id was null on initial save, do it again
$interest->created_by_team_id = $request->input('church_id');
$interest->save();
// deal with tags
$interest->interest_tags()->sync(array_filter((array) $request->input('interest_tags')));
// deal with custom fields
if (! empty($item['meta'])) {
$interest->syncMeta($item['meta']);
}
}
} else {
$model::insert($insert_item);
}
}
$rows = count($insert);
$updates = count($update);
$table = Str::plural($modelName);
File::delete($path);
$redirect = $request->input('redirect', false);
return redirect()->to($redirect)->with('message', trans(($updates > 0 ? 'global.app_imported_rows_to_table_with_updates' : 'global.app_imported_rows_to_table'),
['rows' => $rows, 'updates' => $updates, 'table' => $table]
));
}
I do not believe this is the proper way and I hope someone comes along and gives the proper answer but this here is my dirty hack. In my dataset, I have a column for lastname and all the records to have any functional purpose must have a last name so I put an -if- statement if (!empty($interest['lastname'])) checking that the 'lastname' not be empty before save.
$for_insert = array_chunk($insert, 10000); // this was 100, but the chunking was causing the system to only import the first 100 records, even though the success message said it imported all of them - LW 1/25/2019
foreach ($for_insert as $insert_item) {
if ($modelName == 'Interest') {
foreach ($insert_item as $item) {
$interest = new $model;
foreach ($item as $field => $value) {
if ($field != 'meta') {
$interest->$field = $value;
}
}
$interest->created_by_id = auth()->user()->id;
$interest->created_by_team_id = $request->input('church_id');
if (!empty($interest['lastname']))
{
$interest->save();
}
// For some reason, created_by_team_id was null on initial save, do it again
$interest->created_by_team_id = $request->input('church_id');
if (!empty($interest['lastname']))
{
$interest->save();
}
So in this manner, the system goes through the process of importing all the rows in the csv whether they have data or not but it only saves those records that have a lastname value. This accomplishes what I need but I know there must be a cleaner way to do it.
I believe there should be a method of doing this in which a record should be skipped only if all the values in a row/record is empty. So if one value is in place it will insert and create an entry but if all the values in a row are empty it will skip entry. Hopefully, someone will come along sometime and provide that more eloquent solution.

SQLSTATE[23000]

I have a trouble about phpmyadmin of laravel
I want to update the data from the view on the db via controller but I get an error occurred
// save all seats
foreach ($request->all() as $key => $param) {
if ($key === '_token') continue;
$data = explode('-', $key);
$bs = new BookedSeat();
$bs->booking_id = $booking->id;
$bs->day_id = str_replace('c', '', $data[0]);
$bs->table_id = str_replace('t', '', $data[1]);
$bs->number = 0;
$bs->status = 'requested';
$bs->save();
}
its an error when i try update data
its my db
Updated
// save all seats
foreach ($request->all() as $key => $param) {
if ($key === '_token') continue;
$data = explode('-', $key);
$bs = new BookedSeat();
$bs->booking_id = $booking->id;
$day = DB::table('days')->where('name',$data[0])->get();
$bs->day_id = $day->id;
$bs->table_id = str_replace('t', '', $data[1]);
$bs->number = 0;
$bs->status = 'requested';
$bs->save();
}

Elastica Filter and Query Array

I'm using a form for an advanced search. The form inputs are representative of the data in the elasticsearch index. My model receives an array of filter terms and query terms.
$data = array(
'Filter' => array(
'FilerId' => 14592
),
'Query' => array(
'FiledDate' => '2015-08-06',
),
);
I'm using a foreach loop to create the filter and query
foreach ($data['Filter'] AS $field => $value) {
$filter = new \Elastica\Filter\Term();
$filter->setTerm($field, $value);
$filterArray[] = $filter;
}
foreach ($data['Query'] AS $field => $value) {
$query = new \Elastica\Query\QueryString($value);
$query->setDefaultOperator('AND')
->setDefaultField($field);
$queryArray[] = $query;
}
$query = new \Elastica\Query();
$query
->setFields(['TranId'])
->setQuery($queryArray)
->setFilter($filterArray);
$search->setQuery($query);
$numberOfEntries = $search->count();
$comma_separated = 0;
if ($numberOfEntries) {
foreach ($search->scanAndScroll() as $scrollId => $resultSet) {
$results = $resultSet->getResults();
$totalResults = $resultSet->getTotalHits();
foreach ($results as $result) {
$fields = $result->getFields('TransId');
$transid[] = $fields['TranId'][0];
} // ... handle Elastica\ResultSet
}
$comma_separated = implode(", ", $transid);
}
return array('transactions' => $comma_separated, 'total' => $totalResults);
I am getting an error and I can't find the reason why?
Here is some updated code. I'm getting results but not what I thought I should get.
$boolFilter = new \Elastica\Filter\BoolFilter();
foreach ($data['Filter'] AS $field => $value) {
$term = new \Elastica\Filter\Term();
$term->setTerm($field, $value);
$boolFilter->addMust($term);
}
$boolQuery = new \Elastica\Query\BoolQuery();
foreach ($data['Query'] AS $field => $value) {
$match = new \Elastica\Query\Match();
$match->setFieldQuery($field, $value)
->setFieldAnalyzer($field, 'whitespace')
->setFieldOperator($field, 'AND');
$boolQuery->addMust($match);
}
$query = new \Elastica\Query();
$query
->setFields(['TranId'])
->setQuery($boolQuery)
->setFilter($boolFilter);
//print $error->getError();
print "<pre>";
print_r ($query->toArray());
print "</pre>";
$search->setQuery($query);
$numberOfEntries = $search->count();
$comma_separated = 0;
if ($numberOfEntries) {
foreach ($search->scanAndScroll() as $scrollId => $resultSet) {
$results = $resultSet->getResults();
$totalResults = $resultSet->getTotalHits();
foreach ($results as $result) {
$fields = $result->getFields('TransId');
$transid[] = $fields['TranId'][0];
} // ... handle Elastica\ResultSet
}
$comma_separated = implode(", ", $transid);
}
return array('transactions' => $comma_separated, 'total' => $totalResults);
Alright! I needed to add the Standard analyzer instead of the whitespace analyzer. The whitespace analyzer works but only breaks the phrase up on spaces. The standard analyzer breaks the phrase up and make the case lower.
https://www.elastic.co/guide/en/elasticsearch/guide/current/analysis-intro.html#analyze-api
$boolFilter = new \Elastica\Filter\BoolFilter();
foreach ($data['Filter'] AS $field => $value) {
$term = new \Elastica\Filter\Term();
$term->setTerm($field, $value);
$boolFilter->addMust($term);
}
$boolQuery = new \Elastica\Query\BoolQuery();
foreach ($data['Query'] AS $field => $value) {
$match = new \Elastica\Query\Match($value);
$match->setFieldQuery($field, $value);
$match->setFieldAnalyzer($field, 'standard');
$boolQuery->addMust($match);
}
$filterQuery = new \Elastica\Query\Filtered();
$filterQuery->setFilter($boolFilter);
$filterQuery->setQuery($boolQuery);
$query = new \Elastica\Query($filterQuery);
$query->setFields(['TranId']);
print "<pre>";
print_r ($query->toArray());
print "</pre>";
$search->setQuery($query);
$numberOfEntries = $search->count();
$comma_separated = 0;
if ($numberOfEntries) {
foreach ($search->scanAndScroll() as $scrollId => $resultSet) {
$results = $resultSet->getResults();
$totalResults = $resultSet->getTotalHits();
foreach ($results as $result) {
$fields = $result->getFields('TransId');
$transid[] = $fields['TranId'][0];
} // ... handle Elastica\ResultSet
}
$comma_separated = implode(", ", $transid);
}
return array('transactions' => $comma_separated, 'total' => $totalResults);

Magento products from attribute

I have the following code, which will get all products from all orders for one logged in customer which works fine. I want to add to this code so that it only returns products from a specified attribute set. I believe I have both bits of code that I need they just won't work together.
Code I want to add to is:
<?php
if (Mage::getSingleton('customer/session')->isLoggedIn()) {
/* Get the customer data */
$customer = Mage::getSingleton('customer/session')->getCustomer();
/* Get the customer's email address */
$customer_email = $customer->getEmail();
$customer_id = $customer->getId();
}
$collection = Mage::getModel('sales/order')->getCollection()->addAttributeToFilter('customer_email', array(
'like' => $customer_email
));
$uniuqProductSkus = array();
foreach ($collection as $order) {
$order_id = $order->getId();
$order = Mage::getModel("sales/order")->load($order_id);
$ordered_items = $order->getAllItems();
foreach ($ordered_items as $item)
{
if (in_array($item->getProduct()->getSku(), $uniuqProductSkus)) {
continue;
} else {
array_push($uniuqProductSkus, $item->getProduct()->getSku());
echo various variables here;
}
}
}
?>
Code I have used before to get products from a specified attribute set
$attrSetName = 'Beer';
$attributeSetId = Mage::getModel('eav/entity_attribute_set')
->load($attrSetName, 'attribute_set_name')
->getAttributeSetId();
//Load product model collecttion filtered by attribute set id
$products = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('name')
->addFieldToFilter('attribute_set_id', $attributeSetId);
You can add this piece of code to make your script work in the foreach loop.
$product = Mage::getModel('catalog/product')->load($sku, 'sku');
$attributeSetModel = Mage::getModel("eav/entity_attribute_set");
$attributeSetModel->load($product->getAttributeSetId());
$attributeSetName = $attributeSetModel->getAttributeSetName();
if(0 == strcmp($attributeSetName, 'Beer') {
//add your logic
}else{
continue;
}
Update:
<?php
if (Mage::getSingleton('customer/session')->isLoggedIn()) {
/* Get the customer data */
$customer = Mage::getSingleton('customer/session')->getCustomer();
/* Get the customer's email address */
$customer_email = $customer->getEmail();
$customer_id = $customer->getId();
}
$collection =
Mage::getModel('sales/order')->getCollection();
$collection->addAttributeToFilter('customer_email', array(
'like' => $customer_email
));
$uniuqProductSkus = array();
foreach ($collection as $order) {
$order_id = $order->getId();
$order = Mage::getModel("sales/order")->load($order_id);
$ordered_items = $order->getAllItems();
foreach ($ordered_items as $item)
{
$item->getProduct()->getSku();
if (in_array($item->getProduct()->getSku(), $uniuqProductSkus)) {
continue;
} else {
$attributeSetModel = Mage::getModel("eav/entity_attribute_set");
$attributeSetModel->load($item->getProduct()->getAttributeSetId());
$attributeSetName = $attributeSetModel->getAttributeSetName();
if(0 == strcmp($attributeSetName, 'Beer')) {
array_push($uniuqProductSkus, $item->getProduct()->getSku());
// echo various variables here;
}else{
continue;
}
}
}
}
print_r($uniuqProductSkus);
?>

Resources