How to push string into array of array in Laravel 5 - multidimensional-array

I used Codeigiter before, i can use
$var[index1][index2][] = $string;
in a foreach loop, it will keep pushing
But now i got error "Cannot use string offset as an array"
foreach ($grandpa as $index1 => $father){
$newArr[$index1] = '';
foreach ($father as $index2 => $son){
$newArr[$index1][$index2][] = $string;
}
}
So that i have the same array structure of grandpa.

Related

Maatwebsite 3.1 import, Queue does not work

My file is excel .xlsx contains more than 20,000 rows, im using Centos 7 with Nginx web server. When i upload a small size file with few rows it works but when i introduce ShouldQueue and WithChunkReading interfaces it fails even if the file is small. Please I need help. Thanks for your time
Here is the error in a log file
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
[2019-07-11 14:48:47] development.ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx" does not exist. on line 344 of file vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
[2019-07-11 14:48:47] development.ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx" does not exist. on line 344 of file vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
Here is a queue error
[2019-07-12 10:11:47][532] Processing: Maatwebsite\Excel\Jobs\QueueImport
[2019-07-12 10:11:47][532] Processed: Maatwebsite\Excel\Jobs\QueueImport
[2019-07-12 10:11:47][533] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][534] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][535] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][535] Failed: Maatwebsite\Excel\Jobs\ReadChunk
Here is my controller function
public function store(Request $request)
{
Excel::import(new HsCodeImport(),"650.xlsx",'local');
return redirect()->back()->withFlashSuccess(__('label.app_success'));
}
Here is my Import file on App\Imports\HsCodeImport.php
<?php
namespace App\Imports;
use App\Exceptions\GeneralException;
use App\Models\Application\Hscode;
use App\Models\ReceiptCode\ReceiptCode;
use Carbon\Carbon;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class HsCodeImport implements ToCollection, WithHeadingRow, ShouldQueue, WithChunkReading
{
use Importable;
protected $receiptCode;
protected $chunk = 500;
protected $hscode_key = 'hscode';
protected $description_key = 'description';
protected $regulatory_status_key = 'regulatory_status';
protected $comment_key = 'comment';
protected $headings = ['hscode','description','regulatory_status','comment'];
public function __construct(/*ReceiptCode $receiptCode*/)
{
// $this->receiptCode = $receiptCode;
}
/**
* #param Collection $collection
* #throws GeneralException
*/
public function collection(Collection $collection)
{
/*fetching the first Collection*/
$columns = $collection->first();
if (!$columns->has($this->headings)) {
/*When file has different headings*/
} else {
/*When the file has expected headings*/
/*Truncate temp table*/
DB::table('hs_code_temps')->truncate();
/*Counting rows on a file*/
$original_file_rows_count = $collection->count();
/*Chunk the file data according #var $chunk*/
$chunks = $collection->chunk($this->chunk);
/*read each chunks insert into Temporary table and validate to get if there is error in each row*/
$chunks->each(function ($item) {
/*Iterate on each chunk*/
$item->toArray();
foreach ($item as $row) {
/* start: Validating row entries */
$error_report = "";
$error = 0;
foreach ($row as $key => $value) {
if (trim($key) == $this->hscode_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
} elseif (trim($key) == $this->description_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
} elseif (trim($key) == $this->regulatory_status_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
}
}
/*Inserting into Temp table*/
DB::table('hs_code_temps')->insert([
'code' => $row[$this->hscode_key],
$this->description_key => $row[$this->description_key],
$this->regulatory_status_key => $row[$this->regulatory_status_key],
$this->comment_key => $row[$this->comment_key],
'receipt_code_id' => 1/*$receiptCode->id*/,
'error' => $error,
'error_report' => $error_report,
'created_at' => Carbon::now(),
]);
/* end: Validating row entries*/
}
});
/*compare total rows with no error to total rows of the file*/
$total_temp_rows_count = DB::table('hs_code_temps')->whereError(0)->count();
if ($total_temp_rows_count != $original_file_rows_count) {
/*When there is error and rows are not equal*/
} else {
/*When there is no error*/
$originalHsCode = new Hscode();
$temp_table = DB::table('hs_code_temps')->get(['code', $this->description_key, $this->regulatory_status_key, $this->comment_key])/*->toArray()*/;
/*Iterate throw the rows in a temp row*/
foreach ($temp_table as $object) {
/*copy data from temp table to origin table*/
$originalHsCode->create(get_object_vars($object));
}
/*Truncate temp table*/
DB::table('hs_code_temps')->truncate();
}
}
}
public function headings(): array
{
return ['HSCode','Description','Regulatory_Status','Comment'];
}
/*public function sheets(): array
{
}*/
public function chunkSize(): int
{
return 500;
}
public function batchSize(): int
{
return 500;
}
}
I expect the job to run a large data to a chunk to be processed
pass false as third parameter to chunk() to disable queuing
$data = [];
Excel::filter('chunk')->load($path)->chunk(1000, function ($results) use (&$data) {
foreach ($results as $row) {
$data[] = $row;
}
}, $shouldQueue = false);
return $data;
I have a similar problem when deplying to heroku ,that points to a problem with the path.:
`ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx"
does not exist. on line 344 of file
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php`
laravel-excel defines local_path variable in config/excel.php, so try changing the path here or check your public_path() where you are geting the problem.
in my case the excemption saved in table failde_jobs is:
"exception": """ InvalidArgumentException: File "/app/storage/framework/laravel-excel/laravel-excel-aCnUQTJT7ADvAnrf1AOEcaCBPLjhauij" does not exist. in /app/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php:135\n
have been trying to see how to change sot that it does not go in the app folder..

PHPUnit check method invoked multiple times with multiple parameters

I have the following class:
class Foo
{
public function importBars(array $array)
{
foreach ($array as $key => $value) {
$this->importBar($key, $value);
}
}
public function importBar($key, $value)
{
// do stuff
}
}
I need to test that importBar is called count($array) times, and that it's called with the right parameters. Using $this->at() is not an option, as the order of the $array elements might change. I have:
public function testImportBars(array $array)
{
// Mock invocation ...
$logicalOrs = array();
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo($key), $this->equalTo($value));
}
$mock->expects($this->exactly(count($array)))
->method('importBar')
->with(call_user_func_array(array($this, 'logicalOr'), $logicalOrs));
}
Which passes the tests. However, when I deliberately make it fail:
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo($key), $this->equalTo(null));
}
... it still passes. It only fails if the $key is incorrect:
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo(null), $this->equalTo(null));
}
... which suggests PHPUnit is only checking if the first parameter passed to Foo::importBar() is correct.
Is there a way to tell PHPUnit to verify arguments to methods when there is more than one?
After some trial and error, here is the closest solution I've come up with:
$rows = array();
foreach ($array as $key => $value) {
$rows[] = array($key, $value);
}
$method = $mock->expects($this->exactly(count($array)))
->method('importBar');
call_user_func_array(array($method, 'withConsecutive'), $rows);
See: http://phpunit.de/manual/4.1/en/test-doubles.html#test-doubles.mock-objects

How can I fetch distinct values of doctrine2 field with type array

I have FOSUser table and the users have roles with data type array, which are saved in the database in a serialized form, i tried doing a distinct query but it returns each row separately, here's how the query looks like ( this is in the user repository file )
public function getAllRoles()
{
$roles = $this->createQueryBuilder("u")
->select("DISTINCT u.roles");
return $roles->getQuery()->execute();
}
The returned value though needs more processing, here's how it looked like with sample data i have of two users
Array
(
[0] => Array
(
[roles] => Array
(
[0] => ROLE_ADMIN
[1] => ROLE_TEST
)
)
[1] => Array
(
[roles] => Array
(
[0] => ROLE_TEST#
)
)
)
I'm wondering if somehow i could get the array with only 3 items
array(ROLE1, ROLE2, ROLE3, ETC)
You can't via SQL, you will need to process the data in PHP with something like the following (quick and dirty example)
public function getAllRoles()
{
$roles = $this->createQueryBuilder("u")
->select("DISTINCT u.roles");
$data = $roles->getQuery()->execute();
$roles = array();
foreach ($data as $row) {
$roles = array_merge($roles, $row['roles']);
}
return $roles;
}

How to export all rows as CSV in ModelAdmin (SilverStripe 3.1)?

Apparently the GridFieldExportButton only exports the currently visible data-set (paginated). Is there a way to make it export all the rows from a model?
Or alternatively: Is there a way to show all rows (eg. bypass pagination), so that the user can perform an export after showing all the rows? I don't want to show all rows all the time (which would probably be possible by setting ModelAdmin::set_page_length(<ridiculouslyHighNumber>);) but only on demand.
You can override ModelAdmin::getExportFields() to define the columns you want to export.
The method needs to return an array with column name as the key, and the db field as the value.
For example:
class MyCustomModelAdmin extends ModelAdmin {
....
public function getExportFields() {
return array(
'FirstName' => 'FirstName',
'Surname' => 'Surname',
'Age' => 'Age'
);
}
}
Solved it by creating a custom subclass of the GridFieldExportButton and using this for my models. The key is to use $gridField->getList(); instead of $gridField->getManipulatedList(); in the generateExportFileData method.
Here's the complete class for anybody interested:
class GridFieldExportAllButton extends GridFieldExportButton {
/**
* Generate export fields for CSV.
*
* #param GridField $gridField
* #return array
*/
public function generateExportFileData($gridField) {
$separator = $this->csvSeparator;
$csvColumns = ($this->exportColumns)
? $this->exportColumns
: singleton($gridField->getModelClass())->summaryFields();
$fileData = '';
$columnData = array();
$fieldItems = new ArrayList();
if($this->csvHasHeader) {
$headers = array();
// determine the CSV headers. If a field is callable (e.g. anonymous function) then use the
// source name as the header instead
foreach($csvColumns as $columnSource => $columnHeader) {
$headers[] = (!is_string($columnHeader) && is_callable($columnHeader)) ? $columnSource : $columnHeader;
}
$fileData .= "\"" . implode("\"{$separator}\"", array_values($headers)) . "\"";
$fileData .= "\n";
}
$items = $gridField->getList();
foreach($items as $item) {
$columnData = array();
foreach($csvColumns as $columnSource => $columnHeader) {
if(!is_string($columnHeader) && is_callable($columnHeader)) {
if($item->hasMethod($columnSource)) {
$relObj = $item->{$columnSource}();
} else {
$relObj = $item->relObject($columnSource);
}
$value = $columnHeader($relObj);
} else {
$value = $gridField->getDataFieldValue($item, $columnSource);
}
$value = str_replace(array("\r", "\n"), "\n", $value);
$columnData[] = '"' . str_replace('"', '\"', $value) . '"';
}
$fileData .= implode($separator, $columnData);
$fileData .= "\n";
$item->destroy();
}
return $fileData;
}
}
Thanks for this!
I had to use this for Members GF in Security Admin.
Created an extension for anyone interested.
class SecurityAdminExtension extends Extension{
function updateEditForm($form){
$gf = $form->Fields()->fieldByName('Root.Users.Members');
$gfConfig = $gf->getConfig();
$gfConfig->removeComponentsByType('GridFieldExportButton');
$gfConfig->addComponent(new GridFieldExportAllButton());
}
}
I while back, I created a little plugin to make it easy to export DataObjects to CSV or Excel files.
https://github.com/firebrandhq/excel-export
It comes with a button you can add to a grid field.
It's got a dependency on PHP-Excel.

A different service for my Flex app using Zend_Amf

I have an iterator service that works fine already and returns a correctly structured values to my flex application through my Zend Amf server
$contacts = array();
mysql_connect( 'localhost', 'root', 'test' );
mysql_select_db( 'test' );
$res = mysql_query( 'SELECT * FROM contact' );
while( $contact = mysql_fetch_assoc($res) ) {
$contacts []= $contact;
}
return $contacts;
However I would like to adjust this so that I can leverage my MVC structure and achieve the same results.
I have placed an excerpt that can be brought to working condition
$contacts = array();
$table = new Model_DbTable_Contact();
$result = $table->fetchAll();
//Return an array to be consumed by my flex application
foreach ($result as $row)
{
/*do something*/
}
return $contacts;
You'll want to look into ValueObjects. Zend_Amf supports those, and it's a good idea to use that. That way you can have objects that are native to both PHP and Flex.
$server->setClassMap('ContactVO', 'Contact');
Your Flex would then have a class:
[Bindable]
[RemoteClass(alias="Contact")]
public class ContactVO
{
}
Would tell your server that you're going to map your Contact class to ContactVO in Flex.
then you could do:
$data = array();
foreach ($result as $row)
{
$data[] = new Contact($row);
//assuming the Contact constructor parses the array data
}
return $data;
and your Contact objects would get to Flex as ContactVO objects
So here I have a function in the logical model for a database table:
public function fetchAll() {
$resultSet = $this->getDbTable()->fetchAll();
$entries = array();
foreach( $resultSet as $row ) {
$entry = new Model_ClosingData();
$entry->setId($row->id)
->setContractMonth($row->monthId)
->setCommodity($row->commodityId)
->setDate($row->date)
->setPrice($row->price)
->setVolume($row->volume)
->setOutstandingInterest($row->outstandingInterest);
$entries[] = $entry;
}
return $entries;
}

Resources