Exporting Laravel Model to Excel but with modification of created_at column to only date not datetime - excel

i tried to modify a collection before returning it to be exported with maatwebsite Excel. The column i tried to modify is the created_date column (the default created_date of laravel) so that when exported to excel, i only get the date not datetime.
i tried:
namespace App\Exports;
use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
class InvoicesExport implements FromCollection
{
public function collection()
{
$temp = Invoice::all();
$len = count($temp);
for($i=0;$i<$len;$i+=1){
$temp[$i]->created_at = $temp[$i]->created_at->format('m/d/Y')
}
return $temp;
}
}
in the controller:
public function export()
{
return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
but, when exported, the result in the excel file is, for example: '07/26/2016T00:00:00.000000Z'
i noticed that the time become zero, and when i tried:
$temp[$i]->created_at = "some random string"
the laravel in webpage return error said that "some random string" cannot be parsed to datetime by Carbon Class constructor.
how can i make the exporting does not construct datetime with the string i give in the 'created_at' column, but just return the plain string instead? if let's say, i can't modify the database so i can't create extra column and extra column for this simple thing is too much, i think.

If you are using Maatwebsite\Excel 2.1 try column formatting by the setColumnFormat($array) method.
If Maatwebsite\Excel 3.1, try with the WithMapping interface.

created_at is marked as 'datetime' in the $cast property of your model by default so when you set it it's automatically cast as date (with Carbon::parse('the value you gave'))
If you want to export your collection with some values formatted you should not mutate the objects of the original objects but create new dedicated objects/arrays that will not interfere with model behavior nor corrupt your existing objects.

Related

How to remove duplicate rows from excel import in Laravel

I am importing an excel file in Laravel 7 that contains employees' records. The file has Columns Employee No. and date. There are duplicate rows that contain the same employee No. and date. I want to store only 1 such record and discard the duplicate rows. Is there any way to do so?
If you're using laravel-excel, you can define rules for validation and check for duplicate records.
In below example, I've checked for duplication for user with email address.
class ModelImport implements ToModel, WithValidation
{
public function rules(): array
{
return [
'1' => \Illuminate\Validation\Rule::unique('users', 'email'),
];
}
}
Then, add skipping errors by implementing Maatwebsite\Excel\Concerns\SkipsOnFailure interface as stated in here
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;
class ModelImport implements ToModel, WithValidation, SkipsOnFailure
{
use Importable, SkipsFailures;
}

Impex Export: Colon in multivalue attribute is escaped by double backslash - How to remove this behavior?

Hybris: 6.3.0.0-SNAPSHOT (the behavior is the same with 6.3.0.21)
When exporting impex, we noticed a difference when exporting a non-multivalue Type attribute versus exporting a multivalue Type attribute.
When exporting String attribute data without colon, a non-multivalue attribute can be exported as Experts, while a multivalue attribute can be exported as Experts|Hybris.
When exporting Type with String attribute data with colons (e.g. URL), the colon is escaped with a double backslash (for multivalue only). A non-multivalue attribute can be exported as https://experts.hybris.com, while a multivale attribute can be exported as https\://experts.hybris.com if there is only 1 value or as https\://experts.hybris.com|https\://help.hybris.com if there are 2 values.
How can I stop the export from escaping the colon? Is there a method I can override to change this behavior? I would like to change the result to https://experts.hybris.com|https://help.hybris.com or to "https://experts.hybris.com"|"https://help.hybris.com".
Business Case: We want to copy the URL from the exported impex, but the URL contains double backslashes. The exported impex is not meant to be reimported.
Notes #`: The URLs are stored in a collection (e.g. Product.newAttribute, where newAttribute is a collection of custom types which has a String). So, the Impex header looks something like "INSERT_UPDATE Product;newAttribute(data)"
Notes #2: (UPDATE: Didn't work) Currently, I'm checking if it's possible with a CSVCellDecorator; this is for import only.
Notes #3: Currently, I'm checking if it's possible with AbstractSpecialValueTranslator.
For this specific case, I created a new translator, extending AbstractValueTranslator. Then, I implemented the exportValue method, joining the string data (which are URLs), without escaping them.
public String exportValue(final Object value) throws JaloInvalidParameterException
{
String joinedString = "";
if (value instanceof Collection)
{
final Collection valueCollection = (Collection) value;
if (!valueCollection.isEmpty())
{
final ArrayList<CustomType> list = (ArrayList<CustomType>) valueCollection;
final StringJoiner joiner = new StringJoiner("|");
for (final CustomType customType : list)
{
// data is a URL
joiner.add(customType.getData());
}
// value would be something like "https://experts.hybris.com|https://help.hybris.com"
joinedString = joiner.toString();
}
}
return joinedString;
}
Reference:
Customization: https://help.hybris.com/1808/hcd/ef51040168d743879c015b7de232ce40.html
I think that might not be possible, since the colon is used to separate keys for referenced types. As in
...;catalogVersion(catalog(id),version);...
...;myCatalog:Staged;...
Why not run search/replace on the result?

Adding detectable Nullable values to CsvHelper

I was wondering if CsvHelper by Josh Close has anything in the configuration I am missing to translate values to null. I am a huge fan of this library, but I always thought there should be some sort of configuration to let it know what values represent NULL in your file. An example would be a column with the value "NA", "EMPTY", "NULL", etc. I am sure I could create my own TypeConverter, but I was hoping there would be an easier option to set somewhere in a config as this tends to be fairly common with files I encounter.
Is there a configuration setting to do this relatively easily?
I found the TypeConversion in the CsvHelper.TypeConversion namespace but am not sure where to apply something like this or an example of the correct usage:
new NullableConverter(typeof(string)).ConvertFromString(new TypeConverterOptions(), "NA")
I am also using the latest version 2.2.2
Thank you!
I think some time in the last seven years and thirteen versions since this question was asked the options for doing this without a custom type map class expanded, e.g.:
csvReader.Context.TypeConverterOptionsCache.GetOptions<string>().NullValues.Add("NULL");
csvReader.Context.TypeConverterOptionsCache.GetOptions<DateTime?>().NullValues.AddRange(new[] { "NULL", "0" });
csvReader.Context.TypeConverterOptionsCache.GetOptions<int?>().NullValues.Add("NULL");
csvReader.Context.TypeConverterOptionsCache.GetOptions<bool>().BooleanFalseValues.Add("0");
csvReader.Context.TypeConverterOptionsCache.GetOptions<bool>().BooleanTrueValues.Add("1");
CsvHelper can absolutely handle nullable types. You do not need to roll your own TypeConverter if a blank column is considered null. For my examples I am assuming you are using user-defined fluent mappings.
The first thing you need to do is construct a CsvHelper.TypeConverter object for your Nullable types. Note that I'm going to use int since strings allow null values by default.
public class MyClassMap : CsvClassMap<MyClass>
{
public override CreateMap()
{
CsvHelper.TypeConversion.NullableConverter intNullableConverter = new CsvHelper.TypeConversion.NullableConverter(typeof(int?));
Map(m => m.number).Index(2).TypeConverter(intNullableConverter);
}
}
Next is setting the attribute on your CsvReader object to allow blank columns & auto-trim your fields. Personally like to do this by creating a CsvConfiguration object with all of my settings prior to constructing my CsvReader object.
CsvConfiguration csvConfig = new CsvConfiguration();
csvConfig.RegisterClassMap<MyClassMap>();
csvConfig.WillThrowOnMissingField = false;
csvConfig.TrimFields = true;
Then you can call myReader = new CsvReader(stream, csvConfig) to build the CsvReader object.
IF you need to have defined values for null such as "NA" == null then you will need to roll your own CsvHelper.TypeConversion class. I recommend that you extend the NullableConverter class to do this and override both the constructor and ConvertFromString method. Using blank values as null is really your best bet though.
I used "ConvertUsing"...
public class RecordMap : CsvHelper.Configuration.ClassMap<Record>
{
public RecordMap()
{
AutoMap();
Map(m => m.TransactionDate).ConvertUsing( NullDateTimeParser );
Map(m => m.DepositDate).ConvertUsing( NullDateTimeParser );
}
public DateTime? NullDateTimeParser(IReaderRow row)
{
//"CurrentIndex" is a bit of a misnomer here - it's the index of the LAST GetField call so we need to +1
//https://github.com/JoshClose/CsvHelper/issues/1168
var rawValue = row.GetField(row.Context.CurrentIndex+1);
if (rawValue == "NULL")
return null;
else
return DateTime.Parse(rawValue);
}
}

CakePHP view variable as datetime instead of string

In my AppController beforeFilter i am saving user data to variables for use in my view. I need to grab the last_login field that is a datetime and then use the dateformat function to display the date i want but cakephp is outputting this variable as a string, is there a way to putput as the format of the table? (datetime).
// Set user variables for each page load
$id = $this->Auth->user('id');
// Set $id
$user_data = $this->User->findById($id);
// Set User Last Login
$user_lastlogin = $user_data['User']['last_login'];
$this->set('lastLogin', $user_lastlogin);
View
<?php echo date_format($lastLogin, 'F jS \at h:i:s A'); ?>
Error
Warning (2): date_format() expects parameter 1 to be DateTime, string given
Firstly your code is messy. Try this:
$this->User->id = $this->Auth->user('id');
$this->set('lastLogin', $this->User->field('last_login'));
Cake has a class for doing dates and times.
echo CakeTime::niceShort($lastLogin);
Generally you should do the data to string in the view, making it part of the controller or model will have a negative impact on your application if you need to do other things with the data.

How can I change column name convention in Grails?

For now I have field "String firstName" it converted to "first_name" and i want "firstname" as default in Hibernate. Is it posible?
5.5.2.1 Table and Column Names
class Person {
String firstName
static mapping = {
table 'people'
firstName column:'firstname'
}
}
You can change the naming strategy for the entire project. From the documentation https://grails.github.io/grails-doc/latest/guide/GORM.html#customNamingStrategy.
By default Grails uses Hibernate's
ImprovedNamingStrategy to convert
domain class Class and field names to
SQL table and column names by
converting from camel-cased Strings to
ones that use underscores as word
separators. You can customize these on
a per-instance basis in the mapping
closure but if there's a consistent
pattern you can specify a different
NamingStrategy class to use.
Configure the class name to be used in grails-app/conf/DataSource.groovy in the hibernate section, e.g.
So, something like this in your DataSource.groovy
dataSource {
pooled = true
dbCreate = "create-drop"
…
}
hibernate {
cache.use_second_level_cache = true
…
naming_strategy = org.hibernate.cfg.DefaultNamingStrategy
}

Resources