I am using laravel-excel to export csv file. To export, the code is like below,
return Excel::download(new Export(results,$header), "test.csv");
And the Export.php file is like,
namespace App\AllClass;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithHeadings;
class Export implements FromCollection,WithHeadings
{
private $myArray;
private $header;
public function __construct($myArray,$header){
$this->myArray = $myArray;
$this->header = $header;
}
public function collection()
{
$data = mb_convert_encoding($this->myArray,"SJIS", "UTF-8");
// dump($data);
return collect($data);
}
public function headings(): array
{
$header = mb_convert_encoding($this->header,"SJIS", "UTF-8");
// dump($header);
return $header;
}
}
As you can see, I am converting the data before creating excel. Without converting I can export perfectly in UTF-8 format. But after converting to shift-jis, it is deleting all Japanese character. However, if I dump the header before returning, it is showing me gibberish data; not empty string like the csv file.
I resolved it.
Let's me share my solution here.
Laravel Excel not support it by default.
But we can do it by simple way.
Get csv content before download: \Excel::raw
Convert to another encoding: mb_convert_encoding
https://docs.laravel-excel.com/3.1/exports/collection.html#storing-raw-contents
Download csv.
$exportedObject= new \App\Exports\ClassExport($exportDataArray, $fileName);
$csvContent = \Excel::raw($exportedObject, $exportedObject->writerType);
$csvContent = mb_convert_encoding($csvContent, 'SJIS', 'auto');
// In my case, I upload my csv to S3.
$storageInstance = \Storage::disk('s3_import_csvs');
$putFileOnStorage = $storageInstance->put($fileName, $csvContent);
In config/excel.php, you should change CSV Settings
'use_bom' => true,
It's work well in Japanese
Related
I need to write a plugin that exports data both in CSV and XLSX formats*.
As a base I follow Vojta's plugin code (1) that uses ImportExport backend behavior.
The main plugin controller DataImportExport inherits a import-export Behavior from the Backend that is located in the ImportExportController.
class DataImportExport extends Controller
{
public$implement = [
'Backend.Behaviors.ImportExportController',
];
...
}
It's that Behavior that has methods to export data into CSV file. Yet, if I want to export into XLSX file I am supposed to add corresponding methods into that behavior, namely into the exporting controller by overriding some of its existing methods. Yet, as I do that inside DataImportExport controller, it does not work... as I try/test the export process remains the same as it was prior to that with only CSV...
One seems to be not able to override/extend the backend behavior, namely modules\backend\behaviors\ImportExportController.php.
For example, at the DataimportExport controller I try to override the exportFromList() method of ImportExportController behavior by adding code for the XLSX export -
Yet, no positive change... as I try it.
class DataImportExport extends Controller
{
public $implement = [
'Backend.Behaviors.ImportExportController',
];
public function __construct()
{
parent::__construct();
BackendMenu::setContext('RainLab.User', 'user', $this->action);
// extending the ImportExportController behavior
\Backend\Behaviors\ImportExportController::extend(function($model) {
$model->addDynamicProperty('tagsCache', null);
$model->addDynamicMethod('writeXLSX', function() use ($model) {
});
$model->addDynamicMethod('getTagsAttribute', function() use ($model) {
if ($this->tagsCache) {
return $this->tagsCache;
} else {
return $this->tagsCache = $model->tags()->lists('name');
}
});
});
}
...
// method to override
public function exportFromList($definition = null, $options = [])
{
...
$response = Response::make();
if ($options['export_type'] == 'csv') {
/*
* Response CSV
*/
$response->header('Content-Type', 'text/csv');
$response->header('Content-Transfer-Encoding', 'binary');
$response->header('Content-Disposition', sprintf('%s; filename="%s"', 'attachment', $filename));
$response->setContent((string) $csv);
} else {
// export into xlsx code
}
return $response;
}
}
Note
Vojta's plugin exports/imports only into/from CSV files.
maybe you should look at https://octobercms.com/plugin/vdomah-excel where you can import and export CSV and Excel files ? The documentation is very well, and i use it on many projects to import datas and it's working well.
best,
Lucas
I'm exporting some Data from a DB and I want to have the 2 columns that I generate Tab separated.
I've already tried to use implode after my fputcsv but it always appears comma separated. Also tried changing my separator (,) to some other character, but a comma is always printed in the CSV.
This is the function that I'm using for it.
public function ResearchExport(Request $request)
{
//Export ProductID and KitID of all the Kits created from the given date to the actual moment
$TubeAddDate = $request->input('TubeAddDate');
$select = DB::table('tubes')->select('TubeBarcodeID', 'ActivationCode')->where('LOG_important', '2')->whereBetween('TubeAddDate', array($TubeAddDate, NOW()))->get();
$tot_record_found=0;
if (count($select)>0) {
$tot_record_found=1;
$CsvData=array('TubeBarcodeID,ActivationCode');
foreach ($select as $value) {
$CsvData[]=$value->TubeBarcodeID.",".$value->ActivationCode.;
}
$filename=date('Y-m-d').".csv"; //stores the file with the date of today as name
$file_path=storage_path().'/'.$filename;
$file = fopen($file_path, "w+");
foreach ($CsvData as $exp_data) {
fputcsv($file, explode(",", $exp_data));
}
fclose($file);
return response()->download($file_path, $filename);
}
return view('InsertForms/download', ['record_found' =>$tot_record_found]);
}
At the moment I'm getting this as output
TubeBarcodeID,ActivationCode
FF01111112,IKG5G-B0FIZ
FF0111113,6XMP8-760Y3
but I expect something tab separated in the CSV like this
TubeBarcodeID ActivationCode
FF01111112 IKG5G-B0FIZ
FF0111113 6XMP8-760Y3
So I actually just solved thanks to one of the commentaries that pointed out my error.
I just had to change my .csv to .xls and then override the third parameter of fputcsv with a "\t".
$filename=date('Y-m-d').".xls"; //stores the file with the date of today as name
$file_path=storage_path().'/'.$filename;
$file = fopen($file_path, "w+");
foreach ($CsvData as $exp_data) {
fputcsv($file, explode(",", $exp_data), "\t");
}
I'm working with Magento 2, I need to read a file through ftp connection. I can login to ftp but I cannot read the csv file. What I did so far (I cut all the unnecessary parts):
use Magento\Framework\File\Csv;
use Magento\Framework\Filesystem\Io\Ftp;
class MyClass {
protected $_csvprocessor;
protected $_ftp;
public function __construct(Csv $csvprocessor, Ftp $ftp) {
$this->_csvprocessor = $csvprocessor;
$this->_ftp = $ftp;
}
public function getCsv() {
$conn = $this->_ftp->open($params); // this works, I can successfully login to ftp
$filecsv = $this->_ftp->read($remotepathtofile); // this gets me the file but it is a string, not an array with the csv data
$this->_csvprocessor->getData($remotepathtofile); // this doesn't work with remote file, only with local path (eg: magentoroot/var/import/file.csv)
}
}
How can I read the csv as an array, as $this->_csvprocessor->getData() would return, but from remote file instead of local?
You need to parse the csv string. Try using the function "fgetcsv". See http://php.net/manual/en/function.fgetcsv.php.
Below the code, you can use to read CSV file an array
use Magento\Framework\App\Bootstrap;
include('app/bootstrap.php');
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$objectManager1 = Magento\Framework\App\ObjectManager::getInstance();
$directoryList = $objectManager1->get('\Magento\Framework\App\Filesystem\DirectoryList');
$path = $directoryList->getPath('media');
$state = $objectManager->get('Magento\Framework\App\State');
$state->setAreaCode('frontend');
$myarray = glob("Book1.csv");
usort($myarray, create_function('$a,$b', 'return filemtime($a) - filemtime($b);'));
if(count($myarray)){
/*This will create an array of associative arrays with the first row column headers as the keys.*/
$csv_map = array_map('str_getcsv', file($myarray[count($myarray)-1]));
array_walk($csv_map, function(&$a) use ($csv_map) {
$a = array_combine($csv_map[0], $a);
});
array_shift($csv_map); # remove column header
/*End*/
$message = '';
$count = 1;
foreach($csv_map as $data){
your code....
}
Hope this will help you enjoy...
You can dump the server file to your local.
$filecsv = $this->_ftp->read($remotepathtofile, $destinationFilePath);
where $destinationFilePath is local file path.
Then use that local file.
I need file upload field to be required for both Create and Update actions, and the required validation and validation of types to be performed in both cases.
This is how my form looks like (Note: It's a form, not an Active Record model):
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\base\Object;
use yii\helpers\FileHelper;
class MyCustomForm extends Model
{
public $file_image;
public function rules()
{
return [
[
[['file_image'], 'file', 'skipOnEmpty' => false, 'extensions' => 'jpg, jpeg, png, bmp, jpe']
]
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
//Scenarios Attributes that will be validated
$scenarios['action_add'] = ['file_image'];
$scenarios['action_edit'] = ['file_image'];
return $scenarios;
}
}
And this is how my controller actions looks like.
The Create action works as expected (on POST request I'm taking the Uploaded File with UploadedFile::getInstance command)
public function actionCreate()
{
$model_form = new MyCustomForm(['scenario' => 'action_add']);
if (Yii::$app->request->isPost && $model_form->load(Yii::$app->request->post())) {
$model_form->file_image = \yii\web\UploadedFile::getInstance($model_form, "file_image");
if($model_form->validate()) {
if(isset($model_form->file_image)){
//I'm uploading my image to some cloud server here
//creating corresponding $model_entity for database, fill with the data from the form and save it
$model_entity->save();
}
}
}
}
But I'm facing with an issue when doing the same on Update action. In database I have the URL of image that is on third party cloud server and I can access it and display the image in my form (so GET request on Update works, I'm getting the corresponding entity from database and fill the form with data). But for POST, file validation is failing, if I don't have file assigned in the model and the POST request for Update is not working.
public function actionUpdate($id)
{
$model_entity = $this->findModel($id);
$image_URL = //I'm having URL to corresponding image here;
$model_form = new MyCustomForm(['scenario' => 'action_edit']);
$model_form_data = [$model_form->formName() => $model_entity->attributes];
$model_form->load($model_form_data);
if (Yii::$app->request->isPost && $model_form->load(Yii::$app->request->post())) {
//if we upload image again this will work
//NOTE: I have another text fields in the form and If I only change them
//and if I don't change the file image, the following result will return NULL and validation will fail
$file_uploaded_image = \yii\web\UploadedFile::getInstance($model_form, "file_image");
if(isset($file_uploaded_image)){
//new image is uploaded on update, this scenario will be OK
} else {
//no image is uploaded on update, this scenario will fail
}
if($model_form->validate()) {
//this will fail if I don't upload image on Update
}
}
}
I have tried many things in Update action, before validation, in order to find a workaround to get the image and validation to not fail. For example:
$dataImg = file_get_contents($image_URL);
$model_form->file_image = $dataImg;
or trying to do get with temporary file:
$dataImg = file_get_contents($dataImg);
$filePath = \yii\helpers\FileHelper::createDirectory("/images/tmp/test.png", 777);
file_put_contents($filePath, $dataImg);
$model_form->file_image = $filePath;
But none of them is working. Is there any solution to this scenario?
Note that I will have to use a Froms (as above) and not the ActiveRecord, since my real project is more complex that example listed.
Write this code in your Model(MyCustomForm) :
class MyCustomForm extends Model
{
public $file_image;
public function rules()
{
return [
[['file_image',],'required','on'=>['create','update']],
[['file_image'], 'file','extensions' => 'jpg, jpeg, png, bmp, jpe'],
];
}
}
Write this code in your actionCreate() :
$model_form = new MyCustomForm();
$model_form->scenario = "create";
Write this code in your actionUpdate() :
$model_form = new MyCustomForm();
$model_form->scenario = "update";
Or you can add scenario by this :
$model_form = new MyCustomForm(['scenario' => 'create']);
I have tried this and it is working.
I have done import in laravel 5 but facing some problem while exporting file.
code is not proper and doesnot give any logic.
I have tried similiar to documentation
public function exportData(Test $test,Excel $excel){
$test=$test->all();
Excel::create('Test excel', function($test) {
$test->sheet('sheet1', function($sheet) {
$sheet->setOrientation('landscape');
});
})->export('xls');
}
how to export csv file from mysql?
I am using "maatwebsite/excel": "~2.0.0" package
You can use INTO OUTFILE in Laravel
public function exportData($file_name) {
$file = public_path()."/downloads/".$file_name; //CSV file is store this path
$query = sprintf("select * from tests INTO OUTFILE '%s' FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'",$file);
\DB::connection()->getpdo()->exec($query);
}
You might consider using the league/csv package. They have an example of exporting a database query to CSV. In your case, it would look something like:
public function exportData() {
// get the data
$data = Test::all();
// get a Writer object for writing to CSV
$csv = League\Csv\Writer::createFromFileObject(new SplTempFileObject());
// add the data to the writer
$csv->insertAll($data);
// output the file
$csv->output('testdata.csv');
}