How to export data of array to excel with each element from an array storing in single row - excel

I am trying to export data to excel using Fast excel. This is easy for straight forward export. However, I have data as follows:
Illuminate\Support\Collection Object
(
[items:protected] => Array
(
[0] => stdClass Object
(
[id] => 1
[name] => name1
[multiple_units] => ["80","103","126","7","10","13"]
)
[1] => stdClass Object
(
[id] => 2
[name] => name2
[multiple_units] => ["30","23","26","7","25","33"]
)
)
)
Where multiple_units is a text column with json_decode. So, now when I try to export data with following code:
public function exportTest()
{
$reviews = DB::table('test_db')->get();
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name,function($review){
$unit_lists = '';
if($review->multiple_units != NULL){
$unit_ids = json_decode($review->multiple_units, true);
foreach($unit_ids as $uk => $uv){
return [
'Name' => $review->name,
'Units' => $uv
];
}
}
});
}
It export to excel file like as:
Name Units
name1 80
name2 30
However, I want to export with each unit being in a single row. For instance,
Name Units
name1 80
name1 103
name1 126
name1 7
name1 10
name1 13
...
...
...
...

As far as I can see, Fast Excel does not allow changing the number of rows in the callback function.
The solution is to manipulate the data before passing it to Fast Excel:
public function exportTest()
{
$reviews = DB::table('test_db')->get()->flatMap(function ($review) {
$items = [];
if ($review->multiple_units != NULL) {
$unit_ids = json_decode($review->multiple_units, true);
foreach ($unit_ids as $uk => $uv) {
$items[] = [
'Name' => $review->name,
'Units' => $uv
];
}
}
return $items;
});
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name);
}
This will map over each review return an array containing name and units for each unit. Then the array is flattened and passed to Fast Excel.
Note: This will ignore any reviews where review->multiple_units == NULL (which includes an empty string)

public function exportTest() {
$reviews = DB::table('test_db')->orderBy('name')->get();
$file_name = 'Review - '.date('Y_m_d').'.xlsx';
return (new FastExcel($reviews))->download($file_name,function($reviews) {
foreach ($reviews as $review) {
# code...
if(!empty($review->multiple_units)) {
$unit_ids = json_decode($review->multiple_units, true);
foreach($unit_ids as $uk => $uv){
return [
'Name' => $review->name,
'Units' => $uv
];
}
}
}
});
}

Related

Codeigniter 4 Query Builder loses SELECT and WHERE condition while executing once more

I am using Codeigniter 4 Query Builder.
Following is code to retrieve data from the database
public function get_data()
{
$where = [
'username' => 'admin'
];
$this->_builder = $this->_db->table('pf_user_master s');
$this->_builder->join('pf_role_master r', 'r.role_id = s.role_id');
$this->_builder->select('username, first_name, last_name, mobile, email, r.role_name, s.status');
if (is_array($where) && !empty($where)) {
$this->_builder->where($where);
}
$first= $this->_builder->get()->getResultArray();
print_r($first);
$second= $this->_builder->get()->getResultArray();
print_r($second);
exit;
}
I am getting the following output:
In variable $first I am getting output as expected
Array
(
[0] => Array
(
[username] => admin
[first_name] => Fisrt
[last_name] => Last
[mobile] =>
[email] => first.last#gmail.com
[role_name] => Admin
[status] => 1
)
)
But in variable $second it Query Builder loses SELECT, WHERE condition and also JOIN.
And prints the output as follows:
Array
(
[0] => Array
(
[user_id] => 1
[username] => admin
[password] => 21232f297a57a5a743894a0e4a801fc3
[first_name] => First
[last_name] => Last
[mobile] =>
[email] => first.last#gmail.com
[role_id] => 1
[status] => 1
[created_by] =>
[created_date] => 2020-09-08 19:30:52
[updated_by] =>
[updated_date] => 2020-09-08 19:32:42
)
[1] => Array
(
[user_id] => 2
[username] => superadmin
[password] => 21232f297a57a5a743894a0e4a801fc3
[first_name] => NewFirst
[last_name] => NewLast
[mobile] =>
[email] => new.new#gmail.com
[role_id] => 1
[status] => 1
[created_by] =>
[created_date] => 2020-09-08 21:51:42
[updated_by] =>
[updated_date] =>
)
)
I've not tested this and it comes from reading the documentation only.
In the CodeIgniter documentation get() has the following parameters
get([$limit = NULL[, $offset = NULL[, $reset = TRUE]]]])
Reference: https://codeigniter.com/user_guide/database/query_builder.html#get
If you were to use
$first= $this->_builder->get(NULL,NULL,FALSE)->getResultArray();
Then your code would become:
public function get_data()
{
$where = [
'username' => 'admin'
];
$this->_builder = $this->_db->table('pf_user_master s');
$this->_builder->join('pf_role_master r', 'r.role_id = s.role_id');
$this->_builder->select('username, first_name, last_name, mobile, email, r.role_name, s.status');
if (is_array($where) && !empty($where)) {
$this->_builder->where($where);
}
$first= $this->_builder->get(NULL,NULL,FALSE)->getResultArray();
print_r($first);
$second= $this->_builder->get()->getResultArray();
print_r($second);
exit;
}
Of course if you were to perform this a 3rd time, the 2nd instance should cause a reset.
The Code is the Documentation ( in most cases ) so we have
In CodeIgniter 4.04 - /system/Database/BaseBuilder.php - Line 1824
The code is
/**
* Get
*
* Compiles the select statement based on the other functions called
* and runs the query
*
* #param integer $limit The limit clause
* #param integer $offset The offset clause
* #param boolean $reset Are we want to clear query builder values?
*
* #return ResultInterface
*/
public function get(int $limit = null, int $offset = 0, bool $reset = true)
{
if (! is_null($limit))
{
$this->limit($limit, $offset);
}
$result = $this->testMode
? $this->getCompiledSelect($reset)
: $this->db->query($this->compileSelect(), $this->binds, false);
if ($reset === true)
{
$this->resetSelect();
// Clear our binds so we don't eat up memory
$this->binds = [];
}
return $result;
}
So the default for $reset, will "clear" what you have observed.
As mentioned by TimBrownlaw
I changed
$first= $this->_builder->get()->getResultArray();
to
$first= $this->_builder->get(NULL, 0 , false)->getResultArray();
and it worked for me as it didn't reset the query as third parameter of get() is for resetting the query

Import excel data given in each repeated 5 rows to one row in database. Laravel 5.8

I've an excel file with following data. The below is the data of 2 users. Each user have 5 rows of details. I need to import the following to 2 rows in database.
The below is my table structure
What I need is, I need to import the excel in such a way, in the table there should be only 2 rows like below.
How can I do this in Laravel 5.8.
Here is my controller code
public function importMovementFile (Request $request){
$this->validate($request, [
'mcafile' => 'required|mimes:xls,xlsx,ods'
]);
$path = $request->file('mcafile')->getRealPath();
$data = \Excel::import(new UsersImport,$path);
return back()->with('success', 'Excel Data Imported successfully.');
}
UserImports
use Maatwebsite\Excel\Row;
use Maatwebsite\Excel\Concerns\OnEachRow;
class UsersImport implements OnEachRow
{
public function onRow(Row $row)
{
$rowIndex = $row->getIndex();
$row = $row->toArray();
UploadMovAnalysisDataFiles::create([
'member_name' => $row[0][$rowIndex],
]);
}
}
Okay I found the solution to this,
We can do this by checking the name inside a for loop. First of all, check whether the name is empty or not, if empty place the first name in name variable and loop throughout. Store each scores of the corresponding name in an object. When another name comes insert the first details and loop through the next and so on.
public function insertExcel
{
$obj= new UploadMovAnalysisDataFiles();
$name ='';
for($i=1;$i<$rows->count();$i++){
if($name==''){
$name = $rows[$i][0];
$id = $rows[$i][1];
$date = date('Y-m-d h:i:s', strtotime($rows[$i][2]));
$visit_date = $date;
//function call
score($rows[$i][3],$rows[$i][4];
}elseif($name==$rows[$i][0]){
//function call
score($rows[$i][3],$rows[$i][4];
}else{
UploadMovAnalysisDataFiles::create([
'member_name' => $name,
'mov_analysis_tag_id' => $id ,
'visit_date' => $date,
'fitness_score' => $obj->fscore,
'knee_score' => $obj->kscore,
'hip_score' => $obj->hscore,
'core_score' => $obj->cscore,
'shoulder_score' => $obj->sscore,
]);
$name = $rows[$i][0];
$id = $rows[$i][1];
$date = date('Y-m-d h:i:s', strtotime($rows[$i][2]));
$visit_date = $date;
//function call
score($rows[$i][3],$rows[$i][4]);
}
}
UploadMovAnalysisDataFiles::create([
'member_name' => $name,
'mov_analysis_tag_id' => $id ,
'visit_date' => $date,
'fitness_score' => $obj->fscore,
'knee_score' => $obj->kscore,
'hip_score' => $obj->hscore,
'core_score' => $obj->cscore,
'shoulder_score' => $obj->sscore,
]);
}
Function to keep each score in an object.
function score($rows[$i][3],$rows[$i][4){
if($rows[$i][3]== 'VSFitness_Score'){
$obj->fscore = $rows[$i][4];
}if($rows[$i][3]== 'knee_Score'){
$obj->kscore = $rows[$i][4];
}if($rows[$i][3]== 'Hip_Score'){
$obj->hscore = $rows[$i][4];
}if($rows[$i][3]== 'Core_Score'){
$obj->cscore = $rows[$i][4];
}if($rows[$i][3]== 'Shoulder_Score'){
$obj->sscore = $rows[$i][4];
}
}

How do I convert an integer to string in CakePHP?

In my CakePHP app when I try to get data like this:
$this->loadModel('Radio');
$posts = $this->Radio->find('all');
the integers are displayed like strings (in debug) :
'Radio' => array(
'idSong' => '4',
'name' => 'batman',
'title' => 'Batman Theme Song'
),
why? the type is int in the DB. I need integers correctly displayed in my JSON files
Not sure if there's a straightforward solution, but you could change the model data using afterfind
Something like
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
if (isset($val['Radio']['idSong'])) {
$results[$key]['Radio']['idSong'] = (int)$results[$key]['Radio']['idSong'];
}
}
return $results;
}

Extending Drupal 7 search

I want to extend default Drupal 7 node search with one additional field.
I alter search form with the following new field:
function mymodule_form_search_form_alter(&$form, &$form_state, $form_id) {
$form['basic']['site'] = array(
'#type' => 'select',
'#options' => array(
'KEY1' => 'TITLE1',
'KEY2' => 'TITLE2',
'KEY3' => 'TITLE3'
)
);
}
I have a field called field_data_field_site.field_site_value which i need to use as a filter in this search.
I've tried to read about hook_search_* functions but didn't get the idea.
My question is the following. How can I extend search form? Anyone have live examples?
The following is the best way I solve this problem.
First of all I need to alter Drupal's search block and search form with my field and define new submit function.
/**
* Implements hook_form_FORM_ID_alter().
*/
function mymodule_form_search_block_form_alter(&$form, &$form_state, $form_id) {
$form['#submit'][] = 'search_form_alter_submit';
$form['site'] = array(
'#type' => 'select',
'#options' => _options(),
'#default_value' => (($_GET['site']) ? $_GET['site'] : '')
);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function mymodule_form_search_form_alter(&$form, &$form_state, $form_id) {
$form['#submit'][] = 'search_form_alter_submit';
$form['basic']['site'] = array(
'#type' => 'select',
'#options' => _options(),
'#default_value' => (($_GET['site']) ? $_GET['site'] : '')
);
}
function _options() {
return array(
'' => 'Select site',
'site-1' => 'Site 1',
'site-2' => 'Site 2'
);
}
Submit function will forward us to default search/node page but with our query. Page would look like search/node/Our-query-string?site=Our-option-selected.
function search_form_alter_submit($form, &$form_state) {
$path = $form_state['redirect'];
$options = array(
'query' => array(
'site' => $form_state['values']['site']
)
);
drupal_goto($path, $options);
}
Next step is to use hook_search_info (Don't forget to turn it on and set as default on admin/config/search/settings page).
/**
* Implements hook_search_info().
*/
function mymodule_search_info() {
return array(
'title' => 'Content',
'path' => 'node',
'conditions_callback' => '_conditions_callback',
);
}
Conditions callback function defined in hook_search_info. We need to provide additional queries to our search.
function _conditions_callback($keys) {
$conditions = array();
if (!empty($_REQUEST['site'])) {
$conditions['site'] = $_REQUEST['site'];
}
return $conditions;
}
Finally, hook_search_execute will filter our content by our query. I used default code from this hook with modifications I need.
/**
* Implements hook_search_execute().
*/
function mymodule_search_execute($keys = NULL, $conditions = NULL) {
// Build matching conditions
$query = db_select('search_index', 'i', array('target' => 'slave'))
->extend('SearchQuery')
->extend('PagerDefault');
$query->join('node', 'n', 'n.nid = i.sid');
// Here goes my filter where I joined another table and
// filter by required field
$site = (isset($conditions['site'])) ? $conditions['site'] : NULL;
if ($site) {
$query->leftJoin('field_data_field_site', 's', 's.entity_id = i.sid');
$query->condition('s.field_site_value', $site);
}
// End of my filter
$query
->condition('n.status', 1)
->addTag('node_access')
->searchExpression($keys, 'node');
// Insert special keywords.
$query->setOption('type', 'n.type');
$query->setOption('language', 'n.language');
if ($query->setOption('term', 'ti.tid')) {
$query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
}
// Only continue if the first pass query matches.
if (!$query->executeFirstPass()) {
return array();
}
// Add the ranking expressions.
_node_rankings($query);
// Load results.
$find = $query
->limit(10)
->execute();
$results = array();
foreach ($find as $item) {
// Build the node body.
$node = node_load($item->sid);
node_build_content($node, 'search_result');
$node->body = drupal_render($node->content);
// Fetch comments for snippet.
$node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
// Fetch terms for snippet.
$node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);
$extra = module_invoke_all('node_search_result', $node);
$results[] = array(
'link' => url("node/{$item->sid}", array('absolute' => TRUE)),
'type' => check_plain(node_type_get_name($node)),
'title' => $node->title,
'user' => theme('username', array('account' => $node)),
'date' => $node->changed,
'node' => $node,
'extra' => $extra,
'score' => $item->calculated_score,
'snippet' => search_excerpt($keys, $node->body)
);
}
return $results;
}
I'd be happy if anyone would give me a better answer.

Drupal hook_search function location

I can't for the life of me figure out where the hook_search function in drupal is located. Is it something I need to add to a file to access?
Hook functions don't exist by name -- they indicate a naming convention that can be followed to respond to that particular "hook"...
An example would be the node_search() function. When the search module calls module_invoke_all('search'), all functions named foo_search(), where foo is the name of an enabled module, will be called. The details of the search hook in particular are found on api.drupal.org.
function hook_search($op = 'search', $keys = null) {
switch ($op) {
case 'name':
return t('content');
case 'reset':
variable_del('node_cron_last');
return;
case 'search':
$find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid '. node_access_join_sql() .' INNER JOIN {users} u ON n.uid = u.uid', 'n.status = 1 AND '. node_access_where_sql());
$results = array();
foreach ($find as $item) {
$node = node_load(array('nid' => $item));
$extra = node_invoke_nodeapi($node, 'search result');
$results[] = array('link' => url('node/'. $item),
'type' => node_invoke($node, 'node_name'),
'title' => $node->title,
'user' => theme('username', $node),
'date' => $node->changed,
'extra' => $extra,
'snippet' => search_excerpt($keys, check_output($node->body, $node->format)));
}
return $results;
}
}

Resources