PHPExcel: is it necessary to getSheet once you have an object? - phpexcel

Ok so PHPExcel loads the file into its objectReader
// 1. Load file
$inputFileType = PHPExcel_IOFactory::identify($this->inputFileName);
$this->LogMsg("FileType identified as :".$inputFileType, "O", $opLog);
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$this->LogMsg("Reader Created successfully", "O", $opLog);
$objReader->setReadDataOnly(true); // if set to read only, it will ignore styling and data validation
$objReader->setLoadSheetsOnly($this->sheetname);
$objReader= $objReader->setReadFilter($filterSubset);
$objPHPExcel = $objReader->load($this->inputFileName);
echo ("File Loaded <br>");
Suppose the data is loaded into object. Now after that, in order to access data, (correct me if I'm wrong) you would normally load the worksheet. Either with or without filters. That's about the only thing documentation tells you how to do (and I've read the developer and user docs).
$worksheet = $objPHPExcel->getSheet(0);
After that, you can transform $worksheet into an array, and you can pretty much work with data in it. Thing is though that for big files, the getSheet method is the one that takes the most time (In my case, 5seconds for a 9Mb excel file).
I was wondering whether loading worksheet is even necessary. What does $objPHPExcel contain once the file is loaded? var_dumping it doesn't enlighten me much because it seems to have a bunch of protected properties which you can't even access from the outside. Is it anything like a $result dataset after a query? Can I work with it rather than load sheets? Are there any methods other than load() that can be used on it? Can you point me towards anything to read other than the documentation?

Excel file consists of many sheets as it is a spreadsheet. Actually all data is stored in sheets even if there is only one sheet.
So to work with data stored in sheet you must load it in memory and make PHPExcel to analyze it. Before it there is no data available to work with.

Related

Can I use PowerBI to access SharePoint files, and R to write those files to a local directory (without opening them)?

I have a couple of large .xlsb files in 2FA-protected SharePoint. They refresh periodically, and I'd like to automate the process of pulling them across to a local directory. I can do this in PowerBI already by polling the folder list, filtering to the folder/files that I want, importing them and using an R script to write that to an .rds (it doesn't need to be .rds - any compressed format would do). Here's the code:
let
#"~ Query ~"="",
//Address for the SP folder
SPAddress="https://....sharepoint.com/sites/...",
//Poll the content
Source15 = SharePoint.Files(SPAddress, [ApiVersion=15]),
//... some code to filter the content list down to the 2 .xlsb files I'm interested in - they're listed as nested 'binary' items under column 'Content' within table 'xlsbList'
//R export within an arbitrary 'add column' instruction
ExportRDS = Table.AddColumn(xlsbList, "Export", each R.Execute(
"saveRDS(dataset, file = ""C:/Users/current.user/Desktop/XLSBs/" & [Label] & ".rds"")",[dataset=Excel.Workbook([Content])[Data]{0}]))
However, the files are so large that my login times out before the refresh can complete. I've tried using R's file.copy command instead of saveRDS, to pick up the files as binaries (so PowerBI never has to import them):
R.Execute("file.copy(dataset, ""C:/Users/current.user/Desktop/XLSBs/""),[dataset=[Content]])
with dataset=[Content] instead of dataset=Excel.Workbook([Content])[Data]{0} (which gives me a different error, but in any event would result in the same runtime issues as before) but it tells me The Parameter 'dataset' isn't a Table. Is there a way to reference what PowerBI sees as binary objects, from within nested R (or Python) code so that I can copy them to a local directory without PowerBI importing them as data?
Unfortunately I don't have permissions to set the SharePoint site up for direct access from R/Python, or I'd leave PowerBI out entirely.
Thanks in advance for your help

How do I save data in R to an existing dataset in an existing Excel file?

I am creating a form in Shiny R and when the user inputs some information, I want that information to then be appended to the bottom of an existing dataset in an existing xlsx file.
So far I've tried using write.xlsx() with append = TRUE to add to an existing file, but this just creates a new sheet in the file. From there I tried specifying the sheet I want the data to be written to (sheet = 'Data'), but it tries to make a new sheet with that name instead and gets mad that it already exists.
Is this something that's even possible with write.xlsx() or will I have to find a different method to do this?
Edit
I think it would actually be helpful if I give a little more info about the app I'm making. The app is also being used to analyze the data in the existing file. This is why I just want to add to it, rather than create a new file.
Edit 2
For the most part, I seem to have things working correctly thanks to the suggestions below in the comments. With the exception of one issue I can't seem to fix. In the form, every time you submit new data it adds an additional column of numbers to the dataset, which I definitely don't want! Is there a way to prevent this from happening? As of now I am using bind_rows() to merge the data and I've also tried rbind(), rbind_all(), smartbind(), and I'm sure maybe one or two more I'm forgetting at the moment, with no luck.

SilverStripe 4.1 Email->addAttachment()?

I have a contact form that accepts a file input, I'd like to attach the file to the email that gets sent from the form.
Looking at the API reference isn't really helping, it states that the function expects a filepath with no clarification on anything beyond that.
The submit action will save a record of the into the database and this works correctly, something like:
$submission = MyDataObject::create();
$form->saveInto($submission);
$submission->write();
an Email object then gets created and sent. Both of these are functioning and working as expected.
Trying to attach the File I've tried:
$email->addAttachemnt($submission->MyFile()->Link());
which is the closest I can get to getting a filepath for the document. Dumping and pasting the resulting filepath being output by that call will download the form but that line throws an error and can't seem to locate the file.
I suspect that I'm misunderstanding what's supposed to be given to the function, clarification would be very much appreciated.
P.S. I don't currently have access to the code, I'm looking for some clarification on the function itself not an exact answer :).
In SilverStripe 4 the assets are abstracted away, so you can't guarantee that the file exists on your webserver. It generally will, but it could equally exist on a CDN somewhere for example.
When you handle files in SilverStripe 4 you should always use the contents of the file and whatever other metadata you have available, rather than relying on filesystem calls to load it.
This is how the silverstripe/userforms module attaches files to emails:
/** #var SilverStripe\Control\Email\Email $email */
$email->addAttachmentFromData(
$file->getString(), // stream of file contents
$file->getFilename(), // original filename
$file->getMimeType() // mime type
);
I would try $email->addAttachment($submission->MyFile()->Filename); If it doesn't work, you may need to prepend $_SERVER['DOCUMENT_ROOT'] to the filename.
$email->addAttachment($_SERVER['DOCUMENT_ROOT'] . $submission->MyFile()->Filename);

Exporting Several XtraGrid Controls to a Single Excel File

I've got several XtraGrid Controls each one containing different information, I get some information about the way in which you can export a XtraGrid to an Excel file in the following direction http://www.devexpress.com/Support/Center/p/Q362120.aspx
Now Is there any way to export the each XtraGrid Control to a single Excel file so that every XtraGrid information is exported to a different excel sheet.
I tried setting the exporting path direction to the same Excel file, but when the first exporting process is done, the second exporting process just overrides the excel file and so on.
I tried using the method described in this direction XtraGrid - Export To Excel , but I wanted to know if there is another way whithout using the interop excel libraries because I have experience some problems when using this library (I mean when using this library you create an Excel process but after you created it you cannot kill it, even though you have used the method that is supposed to do that).
Any help would be welcomed.
I just wanted to provide a more complete answer, since it took a while for me to get a solution together using D..'s answer.
And yes - it looks like I'm trying to print something, but I'm just exporting to Excel, I promise.
using DevExpress.XtraPrinting;
using DevExpress.XtraPrintingLinks;
using DevExpress.XtraGrid;
class whatever
{
GridControl grid1;
GridControl grid2;
//.....
public void exportToExcel()
{
using (var saveDialog = new SaveFileDialog())
{
saveDialog.Filter = "Excel (.xlsx)|*.xlsx";
if (saveDialog.ShowDialog() == DialogResult.OK)
{
var printingSystem = new PrintingSystemBase();
var compositeLink = new CompositeLinkBase();
compositeLink.PrintingSystemBase = printingSystem;
var link1 = new PrintableComponentLinkBase();
link1.Component = grid1;
var link2 = new PrintableComponentLinkBase();
link2.Component = grid2;
compositeLink.Links.Add(link1);
compositeLink.Links.Add(link2);
var options = new XlsxExportOptions();
options.ExportMode = XlsxExportMode.SingleFilePageByPage;
compositeLink.CreatePageForEachLink();
compositeLink.ExportToXlsx(saveDialog.FileName, options);
}
}
}
}
Hope it saves somebody a little time.
To do that you will want to add a printableComponentLink to each gridControl, and then Create a compositeLink that you can add each of the printableComponent links to.
This link may prove DevExpress KB Article may prove useful as it has an example of that.
Then you will use the compositeLink.ExportToXlsx method. If you create XlsxExportOptions with the XlsxExportOptions.ExportMode property equal to SingleFilePageByPage and pass it to the CompositeLink.ExportToXlsx method, every page will be exported to a separate sheet.
In above code, compositeLink.ExportToXlsx failed for me--no such method. Of course I am using V10.2.5, which is old. I suggest this link from the DEVXPRESS site that uses the ShowPreviewDialog method which allows exporting in a number of different formats. The link also shows how to do some customization of the output.
https://documentation.devexpress.com/#WindowsForms/clsDevExpressXtraPrintingLinksCompositeLinktopic

How can I associate many existing files with drupal filefield?

I have many mp3 files stored on my server already from a static website, and we're now moving to drupal. I'm going to create a node for each audio file, but I don't want to have to upload each file again. I'd rather copy the files into the drupal files directory where I want them, and then associate the nodes with the appropriate file.
Any ideas on how to accomplish that?
Thanks!
I am not sure if I am going to propose a different approach or if I am about to tell with different words what you already meant with your original question, but as you want the nodes to be the files, I would rather generate the nodes starting from the files, rather than associating existing nodes with existing files.
In generic terms I would do it programmatically: for each existing files in your import directory I would build the $node object and then invoke node_save($node) to store it in Drupal.
Of course in building the $node object you will need to invoke the API function of the module you are using to manage the files. Here's some sample code I wrote to do a similar task. In this scenario I was attaching a product sheet to a product (a node with additional fields), so...
field_sheet was the CCK field for the product sheet in the product node
product was the node type
$sheet_file was the complete reference (path + filename) to the product sheet file.
So the example:
// Load the CCK field
$field = content_fields('field_sheet', 'product');
// Load the appropriate validators
$validators = array_merge(filefield_widget_upload_validators($field));
// Where do we store the files?
$files_path = filefield_widget_file_path($field);
// Create the file object
$file = field_file_save_file($sheet_file, $validators, $files_path);
// Apply the file to the field, this sets the first file only, could be looped
// if there were more files
$node->field_scheda = array(0 => $file);
// The file has been copied in the appropriate directory, so it can be
// removed from the import directory
unlink($sheet_file);
BTW: if you use a library to read MP3 metadata, you could set $node->title and other attributes in a sensible way.
Hope this helps!
The file_import module doesn't do exactly what you want (it creates node attachments instead of nodes), but it would be relatively simple to use that module as guidance along with the Drapal API to do what you want.

Resources