WithChunkReading reads rows beyond the maximum rows filled - laravel-5.8

I am trying to import excel file over 6610 records, with Maatwebsite-excel v3.1. I have implemented the import class that implements ChunkReading too. After inserting the last record in database,the excel-import implementation even considers 6611th record (6612th row) that is sending empty placeholders for data insertion in database.
Here is some code,
class UsersImport implements ToCollection, WithHeadingRow, WithChunkReading
{
public $count = 0;
public function collection(Collection $rows)
{
//insertion of $rows data in database
}
public function chunkSize() : int {
return 300;
}
}
I have been scratching my head since many hours. But I am unable to understand what is exactly happening.
I am using Ubuntu. And file format is .xlsx.
Kindly help me with the stuff. Thanks in advance.

It was simply a mistake of some white space left in the row beyond the filled rows. I purposefully deleted all the empty rows from 6612th row to max rows in that sheet, and my problem was solved.

Related

how to apply dropdown list to given column range or entire column Laravel excel

Hi There I am using Maatwebsite/Laravel-Excel package to create my excel sheet. i have many dropdown list and i am able to add it for particular cell. i want to add drop down in entire column or in the give column range. can you please guide me how to apply drop down list for entire column please ?
see this is the peace of code
$objValidation2 = $sheet->getCell('E1')->getDataValidation();
above code currently puts drop down in cell E1 only. how can i specify particular cell range to put drop down in the given range
You need to get the row count you need to export.
then try,
for($i=1; $i<=$this->rowCount; $i++){
$objValidation2 = $sheet->getCell('E'.$i)->getDataValidation();
}
For getting row count try using public variable and set it when take the dataset.
For example.
namespace App\Exports;
use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
class InvoicesExport implements FromCollection
{
public $rowCount = 0;
public function collection()
{
$invoices = Invoice::all()
$this->rowCount = invoices->count();
return $invoices;
}
}

Count multiple columns in Laravel query builder

I'm studying laravel query builder's "count"
I would like to count column name 'q12a' and 'q18a'
I can count total records useing below code.
public function count()
{
$total_projects = Book::count();
return view('count')->with(['total'=>$total_projects]);
}
However I'm having problem multiple columns
I had been searching count multiple columns and trying below code and I got
Error Call to a member function count() on int
Dear matiaslauriti helping me and I change code as below.
UPDATED
public function sum_ttl()
{
$q18a_count = DB::table('books')->count('q12a')->count('q18a');
return view('sum_ttl', compact('q12a','q18a'));
}
Could you teach me how to write correct code at controller and blade file please?
You are nearly there. count will return the count of your desired columns (* by default). So you want to do something like:
public function sum_ttl()
{
$q12aCount = Books::count('q12a');
$q18aCount = Books::count('q18a');
return view('sum_ttl', compact('q12aCount', 'q18aCount'));
}
If you want to share the exact SQL query you want to execute, I could try to "translate" it to Eloquent.

How to select multiple row values coma separated in laravel

I am trying to get all the ids with coma separated while doing eloquent relationship.
So here is my current queries
Divrank::where('division_id', 591)->with('meta')->orderBy('position', 'asc')->get()
Divrank table has a one to many relation with Divrankmeta model. So with meta I am trying to return
public function meta(){
return $this->hasOne(Divrankmeta::class)->selectRaw('id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed, sum(totalSets) as totalSets, sum(totalGames) totalGames')
->groupBy('divrank_id');
}
So far this query works fine..
I get the result like this screenshot
Ok so in my Divrankmeta model, I have a column called winAgainst and it can have some ids and some left null. So with the meta relation I want to retrieve winAgainst ids with coma separated string inside meta object.
For better understanding, here is how Divrankmeta table looks like
How can I do this?
Thank you.
The relation you created is one-to-one not one-to-many. That's why you are getting a meta object of the first matched row instead of an array that contains all related meta records.
I never put the modification codes into the eloquent functions. Those codes seem belongs to somewhere else. From my perspective, using "resources" and modifying the data there is a better idea.
If you chose the do so:
// Divrank.php
public function metas()
{
return $this->hasMany('App\Models\Divrankmeta');
}
// Divrankmeta.php
public function divrank()
{
return $this->belongsTo('App\Models\Divrank');
}
// DivrankController
public function index()
{
return DivrankResource::collection(Divrank::with("metas")->all());
}
Create a resource file.
php artisan make:resource DivrankResource
Now, you can modify your Divrank collection on the resource file before your controller returns it.
public function toArray($request)
{
$metaIds = [];
forEach($this->metas as $meta) {
array_push($metaIds, $meta['id']);
}
$this['metaIds'] = $metaIds;
return parent::toArray($request);
}
I'm not able to test this code. But it will probably work. If you don't want to use resources, you can create the same functionality in your controller as well. Bu we like to make controllers as short as possible.
Ok I think I solved it, These are the changes I did. Thanks
return $this->hasOne(Divrankmeta::class)
// ->selectRaw('id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed,
// sum(totalSets) as totalSets, sum(totalGames) totalGames')
->select(\DB::raw("id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed,
sum(totalSets) as totalSets, sum(totalGames) totalGames, GROUP_CONCAT(winAgainst) as winAgainst"))->groupBy('divrank_id');

Yii2: Eagerly selecting calculated column and loading value into model-property

I thought I know every aspect of Yii2 in the meantime, but this one gives me headaches.
Situation
Two tables: Client and Billings. The Client-Table holds a regular list of clients. The Billing-table has several entries for each client (1:n).
Problem
I want to fetch a calculated DB-Field together with the row itself and access it via a virtual property of the model.
Key is that it gets calculated and selected together with the row itself. I know I can achieve something similliar with a regular virtual getter calculating the amount...but this is not at the same time as the select itself.
My Plan
In the query-object of the client-model i tried to add an an additional select (addSelect-Method) and give the field an alias. Then I added the alias of this select with the attributes-method of the model. Somehow this didn't work.
My Question
Does someone of you know the right way to achieve this? As this is a very common problem, I can not imagine this beeing too hard. I just somehow can't find the solution.
Sample code:
echo $client->sumOfBillings should output the contents of the corresponding property within the client-model. The contents of this property should be filled when fetching the client-row itself and not at the moment the property gets called.
I actual found the answer myself. Here is how you do it:
Query object
The fetching of all the Yii2-Models is done via their corresponding Query-Object. This object is retrieved via the models find()-Method. If you override this method, you can return your own query-object for that class. In the example above my model looks like this:
class Client extends \yii\db\ActiveRecord
{
//...
public static function find()
{
return new ClientQuery(get_called_class());
}
//...
}
Now within the Query-Objects init()-Method we can add the corresponding additional selects:
public class ClientQuery extends \yii\db\ActiveQuery
{
public function init()
{
parent::init();
//prepare subquery for calculation
$sub = (new Query())
->select('SUM(billing_amount)')
->from('billing')
->where('billing.client_id = client.id');
$this->addSelect(['client.*', 'sumBillings'=>$sub]);
}
}
We are now done with the query-Object. What have we done now? When selecting a client the sum gets calculated and loaded as well. But how do we access it? This was the hard part where I struggeled. The solution lies within the ActiveRecord-class.
Possibilities to populate the model with calculated data
There are several possibilities to load this data into the model-class. To understand what options we have, we can check out the populateRecord($record, $row)-method of the BaseActiveRecord-class:
/**
* Populates an active record object using a row of data from the database/storage.
*
* This is an internal method meant to be called to create active record objects after
* fetching data from the database. It is mainly used by [[ActiveQuery]] to populate
* the query results into active records.
*
* When calling this method manually you should call [[afterFind()]] on the created
* record to trigger the [[EVENT_AFTER_FIND|afterFind Event]].
*
* #param BaseActiveRecord $record the record to be populated. In most cases this will be an instance
* created by [[instantiate()]] beforehand.
* #param array $row attribute values (name => value)
*/
public static function populateRecord($record, $row)
{
$columns = array_flip($record->attributes());
foreach ($row as $name => $value) {
if (isset($columns[$name])) {
$record->_attributes[$name] = $value;
} elseif ($record->canSetProperty($name)) {
$record->$name = $value;
}
}
$record->_oldAttributes = $record->_attributes;
}
As you can see, the method takes the raw-data ($row) and populates the model instance ($record). If the model has either a property or a setter-method with the same name as the calculated field, it will be populated with data.
Final code of Client-Model
This is my final code of the Client-model:
class Client extends \yii\db\ActiveRecord
{
private $_sumBillings;
//...
public static function find()
{
return new ClientQuery(get_called_class());
}
public function getSumBillings()
{
return $this->_sumBillings;
}
protected function setSumBillings($val)
{
$this->_sumBillings = $val;
}
//...
}
The populateRecord()-method will find the setter-method ($record->canSetProperty($name)) and call it to fill in the calculated value. As it is protected, it is otherwise readonly.
VoilĂ ...not that hard actually and definitely useful!

Laravel 4: Keeping a table Relationship when reducing structure into several tables

History:
DB: Tables clients and titles
A Client can have many titles but a title can only have one client. So i will use a simple one-to-many relationship as illustrated below:
Client Model
class Client extends Eloquent {
public function titles(){
return $this->hasMany('titles');
}
}
Then i simply use the following to get the requested data for the selected title
$clientTitles = Client::find(1)->titles;
All in all this should list all client associated titles.
My question really comes to this as i am looking to split my data within my titles table into smaller tables as i also use some aspects of the titles data somewhere within the system and do not need to get all of the title details every time.
So i would have another three tables related to the titles data table
Titles, Title_Artwork, Title_Details, Titles_List
Now if i use the same as above i will get all the data within the titles table, but not the other three. So how can i then update my relationship to then scrape the other three title tables so when i need to, i can get all the data, rather.
Or is there another way to do this or NO keep to what i have done an just limit the call to the fields i require?
From what I understood, And lets assume that your Titles model is some what like-
class Titles extends Eloquent{
public function titleartwork(){
return ..
}
public function titledetails(){
return ..
}
public function titlelist(){
return ..
}
}
And your client model is-
class Client extends Eloquent {
public function titles(){
return $this->hasMany('titles');
}
}
So in order to get the data of any of these tables Title_Artwork, Title_Details, Titles_List
you can do this
$clientTitles = Client::with('Titles','Titles.titleartwork','Titles.titlelist')->where('id','=',1)->get();
In terms of Laravel it is known as Eager Loading, to know more you can check the doc
It will also work with multiple nesting, I mean if your Title_Artwork also contains relationship like-
class TitleArtwork extends Eloquent{
public function sometable(){
return ..;
}
}
Then you can get the data of sometable using
$clientTitles = Client::with('Titles','Titles.titleartwork.sometable','Titles.titlelist')->where('id','=',1)->get();

Resources