I am exporting an excel using Laravel excel 3.1 by Maatwebsite. I want to map it with 2 headings and display it one below the other
I'm using WithHeadings, WithMapping, FromArray
I'm getting the records, just the format that needs correction
<?php
namespace App\Exports;
use Modules\Program\Entities\Program;
use Modules\report\Entities\report;
use DB;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithMapping;
class reportPerDaySheet implements FromArray, WithTitle, WithHeadings, ShouldAutoSize, WithMapping
{
private $year;
private $day;
private $month;
public function __construct(int $year, int $month, int $day)
{
$this->year = $year;
$this->day = $day;
$this->month = $month;
}
public function array():array
{
$reportOut = DB::table('reports')->join('programs','programs.program_id','=','reports.program_id')->whereMonth('report_dateofreport', $this->month)->whereday('report_dateofreport', $this->day)->get()->toArray();
return $reportOut;
}
public function map($reportOut):array
{
return [
[
$reportOut->program_programname,
$reportOut->program_projectlead,
$reportOut->program_dse,
$reportOut->program_extserviceprovider,
$reportOut->program_programid,
$reportOut->program_datatype,
],
[
$reportOut->report_id,
$reportOut->report_date,
$reportOut->report_url,
$reportOut->report_username,
$reportOut->report_reportertype,
$reportOut->report_productname,
$reportOut->report_verbatim,
$reportOut->report_priority,
$reportOut->report_aeraised,
]
];
}
public function title(): string
{
return $this->day .' '. date("F", mktime(0,0,0,$this->month,1)) .' '. $this->year;
}
public function headings(): array
{
return[
[
'Program Name',
'Project Lead',
'DS&E Contact',
'Name of external service provider',
'Prepared By',
'External Service Provider Contact Information',
'Time Period Covered',
'Program ID',
'Date of Report',
'Data Type',
'Signature'
],
[
'Id',
'Date of report',
'Date',
'URL',
'Username',
'Reporter Type',
'Product Name',
'Verbatim',
'Priority',
'AE Raised',
'User',
'Date From',
'Date Till',
'Record Created At',
'Record Updated At'
]
];
}
}
Current Output:
Desired Output:
In your situation it would be recommended to build the array including the headers within the array() method. Heading rows will always be displayed as the first x rows. (Depending on how many arrays you return)
I ran into a similar situation where i needed to add headings at certain rows,
Think of the function map() as a foreach() it loops through all your data which means you can add a few checks in and add your headings as an additional row.
have a look at the laravel excel docs
Example of map function:
public function map($reportOut): array
{
if($this->addHeadingRow == 1) {
$this->addHeadingRow = 0; // for my use case I only want to add the heading once
$map = [
[], // add an empty array if you would like an spacer row
[
'heading 1',
'heading 2',
'and so on...'
]
];
}
else{
$map = [
$reportOut->program_programname,
$reportOut->program_projectlead,
$reportOut->program_dse,
$reportOut->program_extserviceprovider,
$reportOut->program_programid,
$reportOut->program_datatype,
];
}
return $map;
}
Related
I need to export data with Laravel Export, but the code return ErrorException: Attempt to read property "second_key" on null.
My code:
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Grid\Exporters\ExcelExporter;
use Maatwebsite\Excel\Facades\Excel;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class DataExporter extends ExcelExporter implements FromQuery, WithMapping, ShouldAutoSize
{
protected $fileName = 'Export Data.xlsx';
public function headings(): array
{
return [
'ID',
'Title',
'Status',
'Gender',
'Data',
];
}
public function map($data): array
{
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$data->json_data->second_key, // <-- Here's the error
];
}
}
I've tried to check using this:
print_r(json_encode($data->json_data));
and this is the result:
{
"id": 282,
"second_key": "second_value",
"third_key": "6200",
"fourth_key": "0000",
"fifth_key": 28
}
I've also done this:
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$data->json_data //Without "second_key"
];
and the excel cell returns the same result:
{
"id": 282,
"second_key": "second_value",
"third_key": "6200",
"fourth_key": "0000",
"fifth_key": 28
}
As #dbf said in the comment section, I have to handle empty rows. I have checked several times in the database, and maybe I missed that one blank row.
Anyway, this is how I handle those values:
if (!isset($data->json_data->second_key)) {
$second_key = '-';
} else {
$second_key = $data->json_data->second_key;
}
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$second_key
];
[Update: csv file is succeed in importing data to mysql database, but xls/xlsx still got 'Undefined offset: 1' error]
When I input the Excel file and submit it to import, what I got is error 'Undefined offset: 1'
When I do dd($row) what I got is somehow working?
array:3 [▼ 0 => 1 1 => "XI TKJ" 2 => "Kelas XI TKJ" ]
Screenshot of dd($row) result
Error:
Data in excel I want to input:
Apparently, there's already data on the table but I don't know if it would affect the result or not:
File that got the error -> jurusanImport.php(updated)
use App\jurusan;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;
class jurusanImport implements ToModel
{
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
use WithConditionalSheets;
public function conditionalSheets(): array
{
return [
'Worksheet 1' => new FirstSheetImport(),
'Worksheet 2' => new SecondSheetImport(),
'Worksheet 3' => new ThirdSheetImport(),
];
}
public function model(array $row)
{
dd($row);
return new jurusan([
'nama_jurusan' => $row[1],
'deskripsi' => $row[2],
]);
}
}
web.php
Route::post('/Admin/Jurusan/import_excel', 'AdminController#import_Jurusan')
->middleware('role:Admin');
Route::get('/admin/Jurusan/List', 'AdminController#showJurusanList')
->middleware('role:Admin');
AdminController.php
public function import_Jurusan(Request $request)
{
$user = Auth::user();
$this->validate($request, [
'file' => 'required|mimes:csv,xls,xlsx'
]);
$file = $request->file('file');
$nama_file = rand().$file->getClientOriginalName();
$file->move('file_teacher',$nama_file);
$import = new jurusanImport;
$import->onlySheets('Worksheet 1');
Excel::import($import, public_path('/file_teacher/'.$nama_file));
Session::flash('sukses','Data Siswa Berhasil Diimport!');
return redirect()->back();
}
public function showJurusanList(Request $request)
{
$user = Auth::user(); // Untuk Photo Profile
$jurusan = jurusan::get(); // Show, atau Get All "Materi"
return view('pages.admin.kelas.showjurusan', compact('jurusan', 'user') );
}
Model jurusan.php
protected $fillable = [
'nama_jurusan', 'deskripsi',
];
protected $table = 'jurusan';
How can I solve this?
You have multiple sheet in your xls file. You can check https://docs.laravel-excel.com/3.1/imports/multiple-sheets.html#selecting-sheets-by-worksheet-index
This is not your actual code. I am just sharing to you for reference.
namespace App\Imports;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;
class UsersImport implements WithMultipleSheets
{
use WithConditionalSheets;
public function conditionalSheets(): array
{
return [
'Worksheet 1' => new FirstSheetImport(),
'Worksheet 2' => new SecondSheetImport(),
'Worksheet 3' => new ThirdSheetImport(),
];
}
}
and in controller
$import = new UsersImport();
$import->onlySheets('Worksheet 1', 'Worksheet 3');
Excel::import($import, 'users.xlsx');
Model - Promo:
...
protected $table = 'promo';
...
public function locations()
{
return $this->belongsToMany(Cities::class, 'cities_promo');
}
Controller in laravel-admin
...
protected function form()
{
$location = Cities::pluck('name', 'id');
$form = new Form(new Promo);
$form->text('title', __('Title'));
$form->textarea('desc', __('Description'));
$form->multipleSelect('locations')->options($location);
return $form;
}
...
The bottom line is that it does not display the values that were previously selected and saved. An empty field is displayed there, where you can select values from the City model.
An intermediate solution was to use the attribute.
It is necessary that the format for multipleSelect (and others) was in array format [1,2,3 ... ,7].
In normal communication, an array of the form is transmitted:
{
['id' => 1,
'name' => 'Moscow',
...
],
['id' => 2,
'name' => 'Ekb',
...
],
}
Therefore, for formalization, I used a third-party attribute "Cities" to the model "Promo".
...
//Add extra attribute
//These attributes will be written to the database, if you do not want
//this, then do not advertise!
//protected $attributes = ['cities'];
//Make it available in the json response
protected $appends = ['cities'];
public function getCitiesAttribute()
{
return $this->locations->pluck('id');
}
public function setCitiesAttribute($value)
{
$this->locations()->sync($value);
}
If there are other suggestions, I am ready to listen.
Thank.
change $location to
$location = Cities::All()->pluck('name', 'id');
you can return $location to know it has value or not
also you can set options manually
$form->multipleSelect('locations')->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
to know it works
Using Yii 2.0 i'm trying to grab some $_POST values in my controller from my view but cannot do this. I will show you my code and talk you through it below.
Models/CaseSearch.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Cases;
/**
* CaseSearch represents the model behind the search form about `app\models\Cases`.
*/
class CaseSearch extends Cases
{
public $category;
public $subcategory;
public $childcategory;
public $newcategory;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['case_id', 'year'], 'integer'],
[['name', 'judgement_date', 'neutral_citation', 'all_ER', 'building_law_R', 'const_law_R', 'const_law_J', 'CILL', 'adj_LR'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Cases::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'case_id' => $this->case_id,
'judgement_date' => $this->judgement_date,
'year' => $this->year,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'neutral_citation', $this->neutral_citation])
->andFilterWhere(['like', 'all_ER', $this->all_ER])
->andFilterWhere(['like', 'building_law_R', $this->building_law_R])
->andFilterWhere(['like', 'const_law_R', $this->const_law_R])
->andFilterWhere(['like', 'const_law_J', $this->const_law_J])
->andFilterWhere(['like', 'CILL', $this->CILL])
->andFilterWhere(['like', 'adj_LR', $this->adj_LR]);
return $dataProvider;
}
public function searchByCategory($category){
$query = Cases::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'category_id' => $category
]);
return $dataProvider;
}
}
Okay so now is my view:
<?php
$form = ActiveForm::begin();
echo $form->field($searchModel, 'category')
->dropDownList(
ArrayHelper::map($allCategory, 'id', 'name'),
[
'onchange'=>'getSubcategory()',
]
);
//To stop errors, if first category not chosen make subcategory and empty drop down.
$subcategory = array(
"empty" => ""
);
echo $form->field($searchModel, 'subcategory')
->dropDownList(
ArrayHelper::map($subcategory, 'id', 'name'),
[
'onchange'=>'getChildcategory()',
]
);
//To stop errors, if second category not chosen make childcategory and empty drop down.
$childcategory = array(
"empty" => ""
);
echo $form->field($searchModel, 'childcategory')
->dropDownList(
ArrayHelper::map($childcategory, 'id', 'name'),
[
//'onchange'=>'getChildCategory()',
'onchange'=>'submitNow()',
]
);
echo '<div class="form-group">';
echo Html::submitButton('Submit', ['class' => 'btn btn-primary']);
echo '</div>';
ActiveForm::end();
Ok, so when i click the submit button i want to capture the value in my controller so that i can use this to alter the results given in the gridview.
When i inspect the element on the drop down lists the names are weird so i am not sure if this is making a different. for example the name for subcategory is actually: CaseSearch[subcategory]
Now for my controller:
public function actionIndex()
{
//
// This is for the first render of index
//
$model = new Cases;
$searchModel = new CaseSearch();
$allCategory = Category::find()->all();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
//
// This is for when i click the submit button on the view. I want it to submit and then grab the subcategory in variable $subtest. I make $subtest = 1 so that when i first render the page it doesn't throw an error and when submitted it should change to the post value
//
$subtest = 1;
if($searchModel->load(Yii::$app->request->post())){
$subtest = $_POST['subcategory'];
}
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'allCategory' => $allCategory,
'model' => $model,
'subtest' => $subtest
]);
}
However when i try to print_r() the variable $subtest in my view i get the error:
Undefined index: CaseSearch[subcategory]
and its for the line:
$subtest = $_POST['CaseSearch[subcategory]'];
In my controller.
Can anyone please advise as i cannot figure out why?
I think your application design is improvable. Read the Yii guide.
However I think the solution to the question is:
$subtest = $_POST['CaseSearch']['subcategory];
Don't use $_GETand $_POST directly in your controller there are some abstraction layer which filter that input.
$get = $request->get();
// equivalent to: $get = $_GET;
$post = $request->post();
// equivalent to: $post = $_POST;
You should use that classes and methods to get your params.
http://www.yiiframework.com/doc-2.0/guide-runtime-requests.html
This is a wierd situation because magento is loading my backend model, its just not calling it when I load and save it. I know this because 1. I see it in my database, 2. when I rename my backend model, my test case fails. Here is my code
It saves my values just fine and completely ignores my afterload and beforesave methods.
TEST CASE
<?php
class Super_Base_Test_Controller_Test extends EcomDev_PHPUnit_Test_Case_Controller {
const DEFAULTSTORE = 1;
public function setUpMocks() {
$this->setCurrentStore(1);
$customer = Mage::getSingleton('customer/customer')
->load(1);
$customer->setCoinBalance(20)
->save();
}
public function setUp() {
$this->setUpMocks();
$data = array(
'customer_id'=>1,
'message'=>'this is a test message',
'income'=>20,
'created_at'=>'9/11/84',
'updated_at'=>'9/11/84',
'current'=>1
);
$this->getRequest()->setParams($data);
}
protected function getTearDownOperation() {
return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
}
backend model
<?php
/**
* Created by PhpStorm.
* User: numerical25
* Date: 3/8/14
* Time: 6:22 PM
*/
class Super_Coin_Model_Customer_Attribute_Coinbalance extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract {
protected function _afterLoad()
{
if (!is_array($this->getValue())) {
$value = $this->getValue();
$this->setValue(empty($value) ? false : unserialize($value));
}
}
protected function _beforeSave() {
if (is_array($this->getValue())) {
$this->setValue(serialize($this->getValue()));
}
}
public function setCoinAmount($amount) {
$this->setValue($amount);
}
}
installation file
$eavsetup->addAttribute('customer', 'coin_balance', array(
'input' => 'text',
'type' => 'decimal',
'label' => 'Customer Coin Balance',
'backend' => 'coin/customer_attribute_coinbalance',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 1, ));
When I set break points, the system completly ignores my methods.
Look at abstract class Mage_Eav_Model_Entity_Attribute_Backend_Abstract. It contains the following public methods: beforeSave() and afterLoad().
There are no _afterLoad() and _beforeSave() methods in that class