I have row with different styles for each cell. I need to duplicate it (copy text, style, size).
I was using following function to do it:
function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to) {
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
$rangeFrom = 'A'.$row_from.':'.$lastColumn.$row_from;
// copy text
$ws_to->fromArray($ws_from->rangeToArray($rangeFrom), null, 'A'.$row_to);
// copy style
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$ws_to->duplicateStyle($ws_from->getStyle($c.$row_from), $c.$row_to);
}
}
However it it VERY slow due to loop but I need it fast because many rows will be copied.
Also I have tried this for style copying:
$rangeTo = 'A'.$row_to.':'.$lastColumn.$row_to;
$ws_to->getStyle($rangeTo)->applyFromArray($ws_from->getStyle($rangeFrom));
But it doesn't work - throws error "Invalid style array passed".
Is there any faster method?
After crawling in PHPExcel sources, I have figured out a lot faster way to duplicate row. It works copying only inside one workbook but it is what I needed. Posting it, maybe someone also had or will have similar problem.
function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to) {
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$cell_from = $ws_from->getCell($c.$row_from);
$cell_to = $ws_to->getCell($c.$row_to);
$cell_to->setXfIndex($cell_from->getXfIndex()); // black magic here
$cell_to->setValue($cell_from->getValue());
}
}
For those on PHP 5.3 or so, Somnium's answer blended with Ravean's comment and adapted for PHP 5.3:
/**
* Copies entire row with formatting and merging
* #param $ws_from
* #param $ws_to
* #param $row_from
* #param $row_to
* #throws PHPExcel_Exception
*/
public function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to)
{
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$cell_from = $ws_from->getCell($c . $row_from);
if ($cell_from->isMergeRangeValueCell()) {
$pCoordinateString = PHPExcel_Cell::splitRange($cell_from->getMergeRange());
$coordinateFromString = PHPExcel_Cell::coordinateFromString($pCoordinateString[0][1]);
$col = $coordinateFromString[0];
$ws_to->mergeCells($c . $row_to . ':' . $col . $row_to);
//$cell->getMergeRange()
}
$cell_to = $ws_to->getCell($c . $row_to);
$cell_to->setXfIndex($cell_from->getXfIndex()); // black magic here
$cell_to->setValue($cell_from->getValue());
}
}
Related
I have 70,000 rows in a MySQL table. I am trying to upload them in Firebase via import JSON. I have exported the table into JSON format. The output was an array. e.g., JSON is as follows -
[
{"question_id":"99","question":"What is your name?"},
{"question_id":"200","question":"What do you do?"}
]
For the correct use of Firebase in mobile apps, I need to import this JSON data as an object, along with GUID like following -
{
"-Lf64AvZinbjvEQLMzGc" : {
"question_id" : 99,
"question" : "What is your name?"
},
"-Lf64AvZinbjvEQLMzGd" : {
"question_id" : 200,
"question" : "What do you do?"
}
}
Since the number of rows are 70,000 (JSON file of this data is 110 MB); inserting individually into Firebase is not possible. So I was trying for a way to generate 70,000 GUID and editing the JSON file to add each one before every object. But, I am stuck at both places. I am using the following class (PushId.php) for generating GUID -
<?php
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
class PushId
{
/**
* Modeled after base64 web-safe chars, but ordered by ASCII.
*
* #var string
*/
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
/**
* Timestamp of last push, used to prevent local collisions if you push twice in one ms.
*
* #var int
*/
private static $lastPushTime = 0;
/**
* We generate 72-bits of randomness which get turned into 12 characters and appended to the
* timestamp to prevent collisions with other clients. We store the last characters we
* generated because in the event of a collision, we'll use those same characters except
* "incremented" by one.
*
* #var array
*/
private static $lastRandChars = [];
/**
* #return string
*/
public static function generate()
{
$now = (int) microtime(true) * 1000;
$isDuplicateTime = ($now === static::$lastPushTime);
static::$lastPushTime = $now;
$timeStampChars = new SplFixedArray(8);
for ($i = 7; $i >= 0; $i--) {
$timeStampChars[$i] = substr(self::PUSH_CHARS, $now % 64, 1);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
$now = (int) floor($now / 64);
}
static::assert($now === 0, 'We should have converted the entire timestamp.');
$id = implode('', $timeStampChars->toArray());
if (!$isDuplicateTime) {
for ($i = 0; $i < 12; $i++) {
$lastRandChars[$i] = floor(rand(0, 64));
}
} else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for ($i = 11; $i >= 0 && static::$lastRandChars[$i] === 63; $i--) {
static::$lastRandChars[$i] = 0;
}
static::$lastRandChars[$i]++;
}
for ($i = 0; $i < 12; $i++) {
$id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1);
}
static::assert(strlen($id) === 20, 'Length should be 20.');
return $id;
}
/**
* #param bool $condition
* #param string $message
*/
private static function assert($condition, $message = '')
{
if ($condition !== true) {
throw new RuntimeException($message);
}
}
}
Following is the PHP code that I wrote to generate 70,000 GUID but it showed error (while the same code is working if I use it to generate 1 GUID only)
require_once('PushId.php');
$vars = new PushId();
$my_file = 'TheGUIDs.txt';
$handle = fopen($my_file, 'w') or die('Cannot open file: '.$my_file);
$i=1;
while($i <= 70000){
$data = $vars->generate();
fwrite($handle, $data);
echo $data;
$i++;
}
fclose($handle);
Edit -1
The error I am getting in generating GUID is -
Notice: Undefined offset: 11 in C:\wamp64\www\firebase-json\PushId.php on line 65
Notice: Undefined variable: lastRandChars in C:\wamp64\www\firebase-json\PushId.php on line 71
The first GUID is complete, e.g. in last run I got -Lf8WPlkkNTUjYkIP4WT, but then I got incomplete GUID -Lf8WPlk------------
First, you forgot to prepend static:: to $lastRandChars in some places:
for ($i = 0; $i < 12; $i++) {
$lastRandChars[$i] = floor(rand(0, 64)); // << here
}
for ($i = 0; $i < 12; $i++) {
$id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1); // << and here
}
Next:
When incrementing previous ID, you missed that you should increment not only last char, but all previous chars as well if they are more than 63.
Sample IDs sequence:
...
-Lf64AvZinbjvEQLMzGw
-Lf64AvZinbjvEQLMzGx
-Lf64AvZinbjvEQLMzGy
-Lf64AvZinbjvEQLMzGz
-Lf64AvZinbjvEQLMzH- <<< on this step last char is reset, and previous one is incremented by one
-Lf64AvZinbjvEQLMzH0
-Lf64AvZinbjvEQLMzH1
...
-Lf64AvZinbjvEQLMzzw
-Lf64AvZinbjvEQLMzzx
-Lf64AvZinbjvEQLMzzw
-Lf64AvZinbjvEQLMzzz
-Lf64AvZinbjvEQLN--- <<< on this step last three chars are reset, and previous one is incremented by one
-Lf64AvZinbjvEQLN--0
-Lf64AvZinbjvEQLN--1
...
Modified increment logic:
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for ($i = 11; $i >= 0; $i--) {
$previousIncremented = false;
for ($j = $i; $j > 0; $j--) {
if (!$previousIncremented) {
static::$lastRandChars[$j]++;
}
if (static::$lastRandChars[$j] == 64) {
static::$lastRandChars[$j] = 0;
static::$lastRandChars[$j - 1]++;
$previousIncremented = true;
} else {
break 2;
}
}
}
I am facing this issue while saving a product programmatically on Magento 2.2.5
In any module, if I do $product->save(); OR $this->productRepository->save($product); inside a loop for multiple products. I get:
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'the-lipstick.html-1' for key 'URL_REWRITE_REQUEST_PATH_STORE_ID' in /home/dev3/www/vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php:228
The error is similar to the one described here : https://www.human-element.com/url-key-specified-store-already-exists-magento-2/
Products save fine with admin area login.
Any suggested fixes so far including the ones modifying the core files (DBStorage.php) do not work on 2.2.5.
What I tried so far:
1. Fix from https://www.human-element.com/url-key-specified-store-already-exists-magento-2/
2. Fix from https://magento.stackexchange.com/questions/210359/magento-2-product-url-rewrite-issue
Please suggest a solution/fix for M 2.2.5
My Fix :
In di.xml -
<preference for="Magento\UrlRewrite\Model\Storage\DbStorage" type="MyCompany\FixUrls\Model\ProductUrlFix" />
In ProductFixUrl write these two functions :
protected function doReplace(array $urls){
$this->deleteOld($urls);
$data = [];
$storeId_requestPaths = [];
foreach ($urls as $url) {
$storeId = $url->getStoreId();
$requestPath = $url->getRequestPath();
// Skip if is exist in the database
$sql = "SELECT * FROM url_rewrite where store_id = $storeId and request_path = '$requestPath'";
$exists = $this->connection->fetchOne($sql);
if ($exists) {
continue;
}
$storeId_requestPaths[] = $storeId . '-' . $requestPath;
$data[] = $url->toArray();
}
try {
$n = count($storeId_requestPaths);
for ($i = 0; $i < $n - 1; $i++) {
for ($j = $i + 1; $j < $n; $j++) {
if ($storeId_requestPaths[$i] == $storeId_requestPaths[$j]) {
unset($data[$j]);
}
}
}
parent::insertMultiple($data);
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
/** #var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urlConflicted */
$urlConflicted = [];
foreach ($urls as $url) {
$urlFound = parent::doFindOneByData(
[
UrlRewriteData::REQUEST_PATH => $url->getRequestPath(),
UrlRewriteData::STORE_ID => $url->getStoreId(),
]
);
if (isset($urlFound[UrlRewriteData::URL_REWRITE_ID])) {
$urlConflicted[$urlFound[UrlRewriteData::URL_REWRITE_ID]] = $url->toArray();
}
}
if ($urlConflicted) {
throw new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException(
__('URL key for specified store already exists.'),
$e,
$e->getCode(),
$urlConflicted
);
} else {
throw $e->getPrevious() ?: $e;
}
}
return $urls;
}
/**
* #param UrlRewrite[] $urls
*
* #return void
*/
public function deleteOld(array $urls)
{
$oldUrlsSelect = $this->connection->select();
$oldUrlsSelect->from(
$this->resource->getTableName(self::TABLE_NAME)
);
/** #var UrlRewrite $url */
foreach ($urls as $url) {
$oldUrlsSelect->orWhere(
$this->connection->quoteIdentifier(
UrlRewrite::ENTITY_TYPE
) . ' = ?',
$url->getEntityType()
);
$oldUrlsSelect->where(
$this->connection->quoteIdentifier(
UrlRewrite::ENTITY_ID
) . ' = ?',
$url->getEntityId()
);
$oldUrlsSelect->where(
$this->connection->quoteIdentifier(
UrlRewrite::STORE_ID
) . ' = ?',
$url->getStoreId()
);
}
// prevent query locking in a case when nothing to delete
$checkOldUrlsSelect = clone $oldUrlsSelect;
$checkOldUrlsSelect->reset(Select::COLUMNS);
$checkOldUrlsSelect->columns('count(*)');
$hasOldUrls = (bool) $this->connection->fetchOne($checkOldUrlsSelect);
if ($hasOldUrls) {
$this->connection->query(
$oldUrlsSelect->deleteFromSelect(
$this->resource->getTableName(self::TABLE_NAME)
)
);
}
}
After a migration and a week digging into the problem the only thing that worked for me was https://www.safemage.com/url-optimization-after-migration-magento-2.html
I had to downgrade to 2.2.7 to use it. It says it works on 2.3 but it does not.
After looking on internet for days i can't find exact solution of this.
Then i found if we change the URLKEY of the category it will not show this error so i have done this.
$category->setPath($parentCategory->getPath())
->setParentId($parentId)
->setName('test1')
->setIsActive(true)
->setUrlKey(rand(1,1000000000));
$category->save();
I use random function to add category in database with random no using ->setUrlKey(rand(1,1000000000)); you can add any thing in this like duplicate category name with some random no etc.
and errors gone if it helps you give an UP. thanks
This question already has answers here:
PHP expects T_PAAMAYIM_NEKUDOTAYIM?
(11 answers)
Closed 9 years ago.
I have building a web site but i have a error code and i couldnt fould a fix it
Error
Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM in /home/eneskura/public_html/administrator/components/com_tz_portfolio/helpers/tz_portfolio.php on line 42
line 42-
$class::addEntry(JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
how i can i fix it?
Site: eneskuray.com php 5.2.17 litespeed
full php
<?php
// No direct access
defined('_JEXEC') or die;
class TZ_PortfolioHelper
{
public static $extension = 'com_content';
/**
* Configure the Linkbar.
*
* #param string $vName The name of the active view.
*
* #return void
* #since 1.6
*/
public static function addSubmenu($vName)
{
$class = 'JHtmlSidebar';
if(!COM_TZ_PORTFOLIO_JVERSION_COMPARE){
$class = 'JSubMenuHelper';
}
$class::addEntry( JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_FIELDS'),
'index.php?option=com_tz_portfolio&view=fields',
$vName == 'fields'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_CATEGORIES'),
'index.php?option=com_tz_portfolio&view=categories',
$vName == 'categories');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_ARTICLES'),
'index.php?option=com_tz_portfolio&view=articles',
$vName == 'articles'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_FEATURED_ARTICLES'),
'index.php?option=com_tz_portfolio&view=featured',
$vName == 'featured'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_TAGS'),
'index.php?option=com_tz_portfolio&view=tags',
$vName == 'tags');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_USERS'),
'index.php?option=com_tz_portfolio&view=users',
$vName == 'users');
}
/**
* Gets a list of the actions that can be performed.
*
* #param int The category ID.
* #param int The article ID.
*
* #return JObject
* #since 1.6
*/
public static function getActions($categoryId = 0, $articleId = 0)
{
$user = JFactory::getUser();
$result = new JObject;
if (empty($articleId) && empty($categoryId)) {
$assetName = 'com_tz_portfolio';
}
elseif (empty($articleId)) {
$assetName = 'com_tz_portfolio.category.'.(int) $categoryId;
}
else {
$assetName = 'com_tz_portfolio.article.'.(int) $articleId;
}
$actions = array(
'core.admin', 'core.manage', 'core.create', 'core.edit', 'core.edit.own', 'core.edit.state', 'core.delete'
);
foreach ($actions as $action) {
$result->set($action, $user->authorise($action, $assetName));
}
return $result;
}
/**
* Applies the content tag filters to arbitrary text as per settings for current user group
* #param text The string to filter
* #return string The filtered string
*/
public static function filterText($text)
{
// Filter settings
$config = JComponentHelper::getParams('com_config');
$user = JFactory::getUser();
$userGroups = JAccess::getGroupsByUser($user->get('id'));
$filters = $config->get('filters');
$blackListTags = array();
$blackListAttributes = array();
$customListTags = array();
$customListAttributes = array();
$whiteListTags = array();
$whiteListAttributes = array();
$noHtml = false;
$whiteList = false;
$blackList = false;
$customList = false;
$unfiltered = false;
// Cycle through each of the user groups the user is in.
// Remember they are included in the Public group as well.
foreach ($userGroups as $groupId)
{
// May have added a group but not saved the filters.
if (!isset($filters->$groupId)) {
continue;
}
// Each group the user is in could have different filtering properties.
$filterData = $filters->$groupId;
$filterType = strtoupper($filterData->filter_type);
if ($filterType == 'NH') {
// Maximum HTML filtering.
$noHtml = true;
}
elseif ($filterType == 'NONE') {
// No HTML filtering.
$unfiltered = true;
}
else {
// Black, white or custom list.
// Preprocess the tags and attributes.
$tags = explode(',', $filterData->filter_tags);
$attributes = explode(',', $filterData->filter_attributes);
$tempTags = array();
$tempAttributes = array();
foreach ($tags as $tag)
{
$tag = trim($tag);
if ($tag) {
$tempTags[] = $tag;
}
}
foreach ($attributes as $attribute)
{
$attribute = trim($attribute);
if ($attribute) {
$tempAttributes[] = $attribute;
}
}
// Collect the black or white list tags and attributes.
// Each lists is cummulative.
if ($filterType == 'BL') {
$blackList = true;
$blackListTags = array_merge($blackListTags, $tempTags);
$blackListAttributes = array_merge($blackListAttributes, $tempAttributes);
}
elseif ($filterType == 'CBL') {
// Only set to true if Tags or Attributes were added
if ($tempTags || $tempAttributes) {
$customList = true;
$customListTags = array_merge($customListTags, $tempTags);
$customListAttributes = array_merge($customListAttributes, $tempAttributes);
}
}
elseif ($filterType == 'WL') {
$whiteList = true;
$whiteListTags = array_merge($whiteListTags, $tempTags);
$whiteListAttributes = array_merge($whiteListAttributes, $tempAttributes);
}
}
}
// Remove duplicates before processing (because the black list uses both sets of arrays).
$blackListTags = array_unique($blackListTags);
$blackListAttributes = array_unique($blackListAttributes);
$customListTags = array_unique($customListTags);
$customListAttributes = array_unique($customListAttributes);
$whiteListTags = array_unique($whiteListTags);
$whiteListAttributes = array_unique($whiteListAttributes);
// Unfiltered assumes first priority.
if ($unfiltered) {
// Dont apply filtering.
}
else {
// Custom blacklist precedes Default blacklist
if ($customList) {
$filter = JFilterInput::getInstance(array(), array(), 1, 1);
// Override filter's default blacklist tags and attributes
if ($customListTags) {
$filter->tagBlacklist = $customListTags;
}
if ($customListAttributes) {
$filter->attrBlacklist = $customListAttributes;
}
}
// Black lists take third precedence.
elseif ($blackList) {
// Remove the white-listed attributes from the black-list.
$filter = JFilterInput::getInstance(
array_diff($blackListTags, $whiteListTags), // blacklisted tags
array_diff($blackListAttributes, $whiteListAttributes), // blacklisted attributes
1, // blacklist tags
1 // blacklist attributes
);
// Remove white listed tags from filter's default blacklist
if ($whiteListTags) {
$filter->tagBlacklist = array_diff($filter->tagBlacklist, $whiteListTags);
}
// Remove white listed attributes from filter's default blacklist
if ($whiteListAttributes) {
$filter->attrBlacklist = array_diff($filter->attrBlacklist);
}
}
// White lists take fourth precedence.
elseif ($whiteList) {
$filter = JFilterInput::getInstance($whiteListTags, $whiteListAttributes, 0, 0, 0); // turn off xss auto clean
}
// No HTML takes last place.
else {
$filter = JFilterInput::getInstance();
}
$text = $filter->clean($text, 'html');
}
return $text;
}
}
ATTETION : some texts deleted for privacy.
The scope resolution operator (::) can only be used on a class referenced using a variable from PHP 5.3 -- you're using 5.2.
You'd have to do JHtmlSidebar::addEntry or JSubMenuHelper::addEntry; you can't do $class::addEntry.
JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS') is not calling a method. It should be:
JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS')
See JText.
T_PAAMAYIM_NEKUDOTAYIM refers to the two colons in a row like this ::. Looking at your code sample:
$class::addEntry( JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
I believe the issue is with JText::(. As per Joomla documentation that should be formatted with an underscore so it is JText::_( so your code would be:
$class::addEntry( JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
Not 100% clear on Joomla internals, but that underscore (_) is actually a function/method of some sort within the JText class. So when you were calling it as JText::( PHP choked because it had no idea what you were trying to do with JText. By adding that underscore (_), it will now actually call a function within a class & do what it has to do.
I read XLS file using PHPExcel. There is cells date column. that data column has two type of cells (Date and Text type cells).
I need to get view value of the cells in the XLS file. So before get value of the cell i want to decided whether that cell is Date cell or Text cell.
How can i get view value of the XLS file cells. Is There method like getCellType(), getViewValueOfCell() or any other method for get view value of cell?
Note: $cell->getType is not a real method in PHPExcel. this pseudo method.
please suggest best logic/method for bellow cell read.
// read view value form date column
if($cell->getType == 'Date'){
$array_data[$rowIndex][$cell->getColumn()] = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'YYYY-MM-DD');
}
else if($cell->getType == 'Text'){
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
this my all XLS read function
$objReader = new PHPExcel_Reader_Excel5();
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load($file_path);
$rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
$array_data = array();
foreach ($rowIterator as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
// if(1 == $row->getRowIndex ()) continue;//skip first row
$rowIndex = $row->getRowIndex();
$array_data[$rowIndex] = array('A' => '', 'B' => '', 'C' => '', 'D' => '');
foreach ($cellIterator as $cell) {
if ('A' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
} else if ('B' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
} else if ('C' == $cell->getColumn()) {
// read view value form date column
if($cell->getType == 'Date'){
$array_data[$rowIndex][$cell->getColumn()] = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'YYYY-MM-DD');
}
else if($cell->getType == 'Text'){
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
} else if ('D' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
}
}
The cell's getDataType() will return the datatype of the value contained in a cell
Valid datatypes are defined in PHPExcel_Cell_DataType:
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';
const TYPE_ERROR = 'e';
Note that there is no datatype for dates or times: dates/times are a datatype of float in MS Excel.
To identify whether a cell contains a date/time value you need to check the numberformat mask. To simplify this, the following methods are available in the PHPExcel_Shared_Date class to identify a numberformat mask as one that relates to a date/time
isDateTime()
/**
* Is a given cell a date/time?
*
* #param PHPExcel_Cell $pCell
* #return boolean
*/
isDateTimeFormat()
/**
* Is a given number format a date/time?
*
* #param PHPExcel_Style_NumberFormat $pFormat
* #return boolean
*/
isDateTimeFormatCode()
/**
* Is a given number format code a date/time?
*
* #param string $pFormatCode
* #return boolean
*/
The API documentation should have identified these for you
I made a couple related threads but this is the one direct question that I'm seeking the answer for. My framework will use Zend_Translate if the php version is 5, otherwise I have to mimic the functionality for 4.
It seems that pretty much every implementation of gettext relies on setlocale or locales, I know there's a LOT of inconsistency across systems which is why I don't want to rely upon it.
I've tried a couple times to get the textdomain, bindtextdomain and gettext functions to work but I've always needed to invoke setlocale.
By the way, all the .mo files will be UTF-8.
Here's some reusable code to parse MO files in PHP, based on Zend_Translate_Adapter_Gettext:
<?php
class MoParser {
private $_bigEndian = false;
private $_file = false;
private $_data = array();
private function _readMOData($bytes)
{
if ($this->_bigEndian === false) {
return unpack('V' . $bytes, fread($this->_file, 4 * $bytes));
} else {
return unpack('N' . $bytes, fread($this->_file, 4 * $bytes));
}
}
public function loadTranslationData($filename, $locale)
{
$this->_data = array();
$this->_bigEndian = false;
$this->_file = #fopen($filename, 'rb');
if (!$this->_file) throw new Exception('Error opening translation file \'' . $filename . '\'.');
if (#filesize($filename) < 10) throw new Exception('\'' . $filename . '\' is not a gettext file');
// get Endian
$input = $this->_readMOData(1);
if (strtolower(substr(dechex($input[1]), -8)) == "950412de") {
$this->_bigEndian = false;
} else if (strtolower(substr(dechex($input[1]), -8)) == "de120495") {
$this->_bigEndian = true;
} else {
throw new Exception('\'' . $filename . '\' is not a gettext file');
}
// read revision - not supported for now
$input = $this->_readMOData(1);
// number of bytes
$input = $this->_readMOData(1);
$total = $input[1];
// number of original strings
$input = $this->_readMOData(1);
$OOffset = $input[1];
// number of translation strings
$input = $this->_readMOData(1);
$TOffset = $input[1];
// fill the original table
fseek($this->_file, $OOffset);
$origtemp = $this->_readMOData(2 * $total);
fseek($this->_file, $TOffset);
$transtemp = $this->_readMOData(2 * $total);
for($count = 0; $count < $total; ++$count) {
if ($origtemp[$count * 2 + 1] != 0) {
fseek($this->_file, $origtemp[$count * 2 + 2]);
$original = #fread($this->_file, $origtemp[$count * 2 + 1]);
$original = explode("\0", $original);
} else {
$original[0] = '';
}
if ($transtemp[$count * 2 + 1] != 0) {
fseek($this->_file, $transtemp[$count * 2 + 2]);
$translate = fread($this->_file, $transtemp[$count * 2 + 1]);
$translate = explode("\0", $translate);
if ((count($original) > 1) && (count($translate) > 1)) {
$this->_data[$locale][$original[0]] = $translate;
array_shift($original);
foreach ($original as $orig) {
$this->_data[$locale][$orig] = '';
}
} else {
$this->_data[$locale][$original[0]] = $translate[0];
}
}
}
$this->_data[$locale][''] = trim($this->_data[$locale]['']);
unset($this->_data[$locale]['']);
return $this->_data;
}
}
Ok, I basically ended up writing a mo file parser based on Zend's Gettext Adapter, as far as I know gettext is pretty much reliant upon the locale, so manually parsing the .mo file would save the hassle of running into odd circumstances with locale issues with setlocale. I also plan on parsing the Zend Locale data provided in the form of xml files.