PhpSpreadsheet - get row without iterating on each cell - phpexcel

I'm using PhpSpreadsheet to easily read from a xls document and insert into a DB after some calculations. I succeeded using examples from the documentation, but I find it sooo complicated I'm sure I missed something and it can be done much more easily.
$worksheet = $this->getWorksheet("file.xls");
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE);
foreach ($cellIterator as $key => $cell) {
$cellValue = $cell->getValue();
if($key == 'A')
$field1 = $cellValue;
if($key == 'B') {
$dateTime = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($cellValue);
$date = $dateTime->format("Y-m-d");
}
if($key == 'C')
$field2 = $cellValue;
if($key == 'D')
$field3 = $cellValue;
if($key == 'E')
$field4 = $cellValue;
}
}
I would have expected something like $row->getCell("A")->getValue() to be available.
So... Have I missed something ?

See the docs on getting the values by column and row directly rather than testing the keys
From the example:
// Get the value from cell B5
$cellValue = $spreadsheet->getActiveSheet()->getCellByColumnAndRow(2, 5)->getValue();
Hope that helps

Here is what I found
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$spreadsheet = $reader->load("test.xlsx");
$sheet = $spreadsheet->getSheet(0);
$nb = 0;
foreach ($sheet->getRowIterator() as $row) {
echo $sheet->getCell("A$nb")->getValue();
echo "<hr>";
$nb++;
}

You have to access somehow each cell.
Example: for the case when you don't know the dimensions of rows and columns ( ... which can have combined letters past single alphabet letters), get iteration for each row and then for each column, and in the end you can have the data parsed into multidimensional array:
$results = [];
$reader = new Xlsx(); // PhpOffice\PhpSpreadsheet\Reader\Xlsx
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load(storage_path('app/temp/' . $file));
$sheet = $spreadsheet->getActiveSheet();
foreach ($sheet->getRowIterator() as $index => $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE); // This loops through all cells, even if a cell value is not set.
$row_content = [];
foreach ($cellIterator as $cell) {
array_push($row_content, $cell->getValue());
}
$results[] = $row_content;
}

Related

Doctrine query builder parenthesis bad place

I have a query that receive some array parameters without any ideas how rows there is. It must return contents with all filters (AND clause), and one or more categories (OR clause).
I can't get results I'd like because parentheses are not a the good place. I should got this SQL rendering:
WHERE (
f3_.idfilter = '87'
AND f5_.idfilter = '90'
AND f7_.idfilter = '154'
AND f9_.idfilter = '165'
)
AND (
c0_.content_category_idcontent_category = 1
OR c0_.content_category_idcontent_category = 3
)
and got this instead:
WHERE (
(
f3_.idfilter = '87'
AND f5_.idfilter = '90'
AND f7_.idfilter = '154'
AND f9_.idfilter = '165'
AND c0_.content_category_idcontent_category = 1
)
OR c0_.content_category_idcontent_category = 3
)
My code:
public function getContentByFiltersAjax($categs, $filters, $offset, $limit) {
$filtersTab = explode(',', $filters);
$query = $this->createQueryBuilder('c');
for ($i = 1; $i <= count($filtersTab); $i++) {
$query = $query
->leftJoin('c.filterfilter', 'f' . $i)
->andWhere('f' . $i . '.idfilter = :filter_idfilter' . $i)
->setParameter('filter_idfilter' . $i, $filtersTab[$i - 1]);
}
$categsTab = explode(',', $categs);
if(sizeof($categsTab) > 1) {
$expr = $query->expr();
$categsTab = explode(',', $categs);
foreach ($categsTab as $key => $value) {
if($key === 0){
$query->andWhere($expr->eq('c.contentCategorycontentCategory', $value));
} else {
$query->orWhere($expr->eq('c.contentCategorycontentCategory', $value));
}
}
} else {
$query
->andWhere('c.contentCategorycontentCategory = :category')
->setParameter('category', $categs);
}
$query
->andWhere('c.status = :status')
->setParameter('status', 'publie');
$query->orderBy('editor.plan', 'DESC');
$query->addOrderBy('c.creationDate', 'DESC');
$query
->setFirstResult($offset)
->setMaxResults($limit);
$result = $query->distinct()->getQuery()->getResult();
return $result;
}
You put the orWhere's inside 1 andWhere like this:
$query->andWhere(
$query->expr->orX(
$query->expr->eq('c.contentCategorycontentCategory', $value1),
$query->expr->eq('c.contentCategorycontentCategory', $value2)
)
);
Or in your foreach loop:
$orX = $query->expr->orX();
foreach ($categsTab as $value) {
$orX->add($query->expr->eq('c.contentCategorycontentCategory', $value));
}
$query->andWhere($orX);

Invalid parameter: token 1 is not defined in the query

Here is my code to filter pets base on a JSON ajax Query
I am getting error follwoing image
public function filter($object, $active=true){
$query = $this->createQueryBuilder('p');
$query->innerjoin('TadpetProfessionalBundle:ProPet', 'pp', 'WITH', 'pp.professionalId = p.id');
$query->innerjoin('TadpetManagerBundle:Pet', 'ppp', 'WITH', 'ppp.id = pp.petId');
$query->where('p.isActive = :active')
->setParameter('active', $active);
if(!empty($object->pets)){
$qString = "";
for($i=1; $i<=sizeof($object->pets); $i++){
if($i == 1){
$qString .= "ppp.name = :petname".$i;
}else{
$qString .= " OR ppp.name = :petname".$i;
}
}
$query->andWhere($qString);
$query->setParameter('petname'+1,$object->pets[0]);
$query->setParameter('petname'+2,$object->pets[1]);
$query->setParameter('petname'+3,$object->pets[2]);
}
return $query->getQuery()->getResult();
}
Help me please
In these lines:
$query->setParameter('petname'+1,$object->pets[0]);
$query->setParameter('petname'+2,$object->pets[1]);
$query->setParameter('petname'+3,$object->pets[2]);
You are adding 'petname' to the numbers, but you should concatenate them:
$query->setParameter('petname'.1,$object->pets[0]);
$query->setParameter('petname'.2,$object->pets[1]);
$query->setParameter('petname'.3,$object->pets[2]);
Also, you could use a loop:
for($i=1; $i<=sizeof($object->pets); $i++){
$query->setParameter('petname'.$i,$object->pets[$i-1]);
}

How to get all data from easyui datagrid

I had try to use the getData e.g.
data = $("#dg").datagrid("getData");`
var total = data.total; (total is 100)`
var rows = data.rows; (rows.length is 25)`
It can result: the total number is correct like 100 records
but the rows return only get the current page rows like 25 rows.
I need to get all of the records (100 rows).
Is there something i missed ? Or how can we do this ? Please help me.
This is because of pagination. let me describe model with pagination for showing 100 row in php.
function get_invoiceinfoList($search_keyword,$custID){
$page = 1;
$rows = 100;
$sort = '';
$order = 'asc';
$offset = ($page - 1) * $rows;
if($custID > 0 && $search_keyword == 0){
$search = " and a.customer_id =$custID";
}else{
$search = "and (b.name like '%$search_keyword%' || a.inv_no like '%$search_keyword%')" ;
}
$vQuery=$this->db->query("SELECT a.inv_id,a.inv_no,a.inv_org,a.inv_date,
a.customer_id,a.heading,a.quot_id,a.total_cost as total_amount,
a.paid_amount,(a.total_cost-a.paid_amount)as due_amount,b.name
from sales_invoice a,view_customer_info b
where
a.customer_id = b.customer_id $search order by a.inv_date DESC limit $offset, $rows");
$result = $vQuery->result();
$rows = array();
foreach ($result as $rowData){
array_push($rows, $rowData);
}
$data['rows'] = $rows;
return $data;
}

Circular References in PHPExcel - infinite loop or wrong result

I am using PHPExcel 1.8.0
I have read the posts regarding circular references, such as this one, but I am still running into issues.
If a spreadsheet contains one circular ref. formula, PHPExcel's calculations do not match MS Excel.
If a spreadsheet contains more than one circular ref, then PHPExcel goes into an infinite loop.
Here are the details of what I've done so far.
Assume a spreadsheet where A1 = B1 and B1 = A1+1, and Excel is set to 100 iterations. Here is my code:
// create reader
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
// load workbook
$objPHPExcel = $objReader->load($this->_path);
// set iterative calculations max count
PHPExcel_Calculation::getInstance($objPHPExcel)->cyclicFormulaCount = 100;
// calculate
$objWorksheet = $objPHPExcel->getSheetByName('Testing');
$data = $objWorksheet->rangeToArray('A1:B1');
echo '<pre>';
print_r ($data);
echo '</pre>';
// release resources
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
MSExcel results in A1 = 99, B1 = 100. My code produces this:
Array
(
[0] => Array
(
[0] => #VALUE!
[1] => #VALUE!
)
)
Further to that, if I add A2 = B2 and B2 = A2+1, and attempt to calculate (A1:B2), it goes into an infinite loop and eventually crashes:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 24 bytes) in C:\xampp\htdocs\cgc\bulldog\application\third_party\PHPExcel\Calculation.php on line 2837
Here is what I've done so far. In _calculateFormulaValue in Calculation.php:
Line 2383: $cellValue = ''; - this is the cause of the #Value! error. I changed that to $cellValue = 0;
Line 2400:
} elseif ($this->_cyclicFormulaCell == '') {
$this->_cyclicFormulaCell = $wsTitle.'!'.$cellID;
This is the cause of the infinite loop. $this->_cyclicFormulaCell does not get re-set to '' after the formula in row 1 is done, so this condition does not work for the formula in row 2.
I fixed this as follows, starting from Line 2389:
if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($wsTitle.'!'.$cellID))) {
if ($this->cyclicFormulaCount <= 0) {
return $this->_raiseFormulaError('Cyclic Reference in Formula');
} elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) &&
($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) {
// Olga - reset for next formula
$this->_cyclicFormulaCell = '';
return $cellValue;
} elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) {
++$this->_cyclicFormulaCount;
if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
// Olga - reset for next formula
$this->_cyclicFormulaCell = '';
return $cellValue;
}
} elseif ($this->_cyclicFormulaCell == '') {
$this->_cyclicFormulaCell = $wsTitle.'!'.$cellID;
if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
// Olga - reset for next formula
$this->_cyclicFormulaCell = '';
return $cellValue;
}
}
After these fixes, if I run $data = $objWorksheet->rangeToArray('A1:B2');, I get the following result:
Array
(
[0] => Array
(
[0] => 100 // should be 99
[1] => 100
)
[1] => Array
(
[0] => 100 // should be 99
[1] => 100
)
)
As you can see, the results from PHPExcel are not consistent with MS Excel. Why is this happening and how can I get around this?
Ok, I managed to debug this. My spreadsheet was very complicated, lots of circular refs. The most challenging is a scenario where A depends on B, B depends on both A and C, and C depends on B.
I also added a maxChange parameter, so the thing works like Excel. Otherwise it takes too long on my spreadsheet.
Anyway, here is a usage example:
$objPHPExcel = PHPExcel_IOFactory::load($path);
$objCalc = PHPExcel_Calculation::getInstance($objPHPExcel);
$objCalc->cyclicFormulaCount = 100;
$objCalc->maxChange = 0.001;
The two files that were modified are: Calculation.php and CalcEngine/CyclicReferenceStack.php
Here is the code (sorry Mark, I can't afford more time to submit it to git properly).
Calculation.php
add these to class properties:
private $_precedentsStack = array();
public $maxChange = 0;
replace _calculateFormulaValue() function with this:
public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
$this->_debugLog->writeDebugLog("BREAKPOINT: _calculateFormulaValue for $cellID");
// Basic validation that this is indeed a formula
// We simply return the cell value if not
$formula = trim($formula);
if ($formula{0} != '=') return self::_wrapResult($formula);
$formula = ltrim(substr($formula,1));
if (!isset($formula{0})) return self::_wrapResult($formula);
// initialize values
$pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL;
$wsTitle = ($pCellParent !== NULL) ? $pCellParent->getTitle() : "\x00Wrk";
$key = $wsTitle.'!'.$cellID;
$data = array(
'i' => 0, // incremented when the entire stack has been calculated
'j' => 0, // flags the formula as having been calculated; can only be 0 or 1
'cellValue' => $pCell->getOldCalculatedValue(), // default value to start with
'precedents' => array(),
'holdValue' => FALSE // set to TRUE when change in value is less then maxChange
);
// add this as precedent
$this->_precedentsStack[] = $key;
// if already been calculated, return cached value
if (($cellID !== NULL) && ( $this->getValueFromCache($wsTitle, $cellID, $cellValue))) {
return $cellValue;
}
$this->_cyclicReferenceStack->getValueByKey($key, $data);
extract($data);
$this->_debugLog->writeDebugLog("iteration # $i");
// if already calculated in this iteration, return the temp cached value
if ($i >= $this->cyclicFormulaCount || $j == 1) {
return $cellValue;
}
// on stack, but has not yet been calculated => return default value
if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($key))) {
if ($this->cyclicFormulaCount <= 0) {
return $this->_raiseFormulaError('Cyclic Reference in Formula');
}
return $cellValue;
}
// calculate value recursively
$this->_cyclicReferenceStack->push($key);
$cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell);
$this->_cyclicReferenceStack->pop();
// everything in precedent stack after the current cell is a precedent
// and every precedent's precedent is a precedent (aka a mouthfull)
while ( $this->_precedentsStack[ count($this->_precedentsStack) - 1 ] != $key ){
$data['precedents'][] = array_pop($this->_precedentsStack);
}
$data['precedents'] = array_unique($data['precedents']);
// check for max change
$oldValue = $this->_extractResult($data['cellValue']);
$newValue = $this->_extractResult($cellValue);
$data['cellValue'] = $cellValue;
$data['holdValue'] = (abs($oldValue - $newValue) < $this->maxChange);
// flag as calculated and save to temp storage
$data['j'] = 1;
$this->_cyclicReferenceStack->setValueByKey($key, $data);
// if this cell is a precedent, trigger a re-calculate
$tempCache = $this->_cyclicReferenceStack->showValues();
foreach ($tempCache as $tempKey => $tempData) {
if ( $tempData['holdValue'] == TRUE && ( in_array($key, $tempData['precedents'])) ) {
$tempData['holdValue'] = FALSE;
}
$this->_cyclicReferenceStack->setValueByKey($tempKey, $tempData);
}
// at the end of the stack, increment the counter and flag formulas for re-calculation
if (count($this->_cyclicReferenceStack->showStack()) == 0) {
$i++;
$this->_precedentsStack = array();
$tempCache = $this->_cyclicReferenceStack->showValues();
foreach ($tempCache as $tempKey => $tempData) {
$tempData['i'] = $i;
if ( ! $tempData['holdValue'] ) $tempData['j'] = 0;
$this->_cyclicReferenceStack->setValueByKey($tempKey, $tempData);
}
$this->_debugLog->writeDebugLog("iteration # $i-1 finished");
}
if ($i < $this->cyclicFormulaCount) {
$cellValue = $this->_calculateFormulaValue($pCell->getValue(), $cellID, $pCell);
} elseif ($cellID !== NULL) {
// all done: move value from temp storage to cache
$this->saveValueToCache($wsTitle, $cellID, $cellValue);
$this->_cyclicReferenceStack->removeValueByKey($key);
}
// Return the calculated value
return $cellValue;
} // function _calculateFormulaValue()
add this helper function:
private function _extractResult($result) {
if (is_array($result)) {
while (is_array($result)) {
$result = array_pop($result);
}
}
return $result;
}
CyclicReferenceStack.php
add a property:
private $_values = array();
add a bunch of functions:
public function setValueByKey($key, $value) {
$this->_values[$key] = $value;
}
public function getValueByKey($key, &$value) {
if (isset($this->_values[$key])) {
$value = $this->_values[$key];
return true;
}
return false;
}
public function removeValueByKey($key) {
if (isset($this->_values[$key])) {
unset($this->_values[$key]);
}
}
public function showValues() {
return $this->_values;
}

Get a cell type using PHPExcel

Hi I have this code to read form excel file and add to database using joomla
try
{
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objPHPExcel = $objReader->load($inputFileName);
}
catch(Exception $e) {
die('Error loading file "'.pathinfo($inputFileName,PATHINFO_BASENAME).'": '.$e->getMessage());
}
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
for($i = 11; $i <= $highestRow; $i++)
{
$rowData = $sheet->rangeToArray('A' . $i . ':' . $highestColumn . $i,
NULL,
TRUE,
True
);
$row = $rowData[0];
$valeur1 = $row[8];
}
I open the file and I read it each row and for each row I read each cell
well some time the row[8] is a formated number for exemple (100100.5) some times not like (100,100.5) or something else
Well I need to know the cell type to make some change if the cell is not a number.
Using
$rowData = $sheet->rangeToArray(
'A' . $i . ':' . $highestColumn . $i,
NULL,
True,
False
);
will give you raw values back from the range rather than formatted values
Alternatively, for an individual cell, you can use
$sheet->getCell('A8')->getDataType();
to get the actual datatype stored in the cell. The list of datatypes is defined in Classes/PHPExcel/Cell/DataType.php
const TYPE_STRING2 = 'str';
const TYPE_STRING = 's';
const TYPE_FORMULA = 'f';
const TYPE_NUMERIC = 'n';
const TYPE_BOOL = 'b';
const TYPE_NULL = 'null';
const TYPE_INLINE = 'inlineStr'; // Rich text
const TYPE_ERROR = 'e';

Resources