How to get real number while importing on Laravel Excel maatwebsite? - php

I'd like to get numbers as the real value while importing a file, e.g:
When I open the csv, cell value: 198610012009011005
But when I import that using Laravel Excel, it'll be formatted to 1.98610012009011E+17
How can I get the real value of the number (198610012009011005) ?
I tried bellow code but it didn't work
$data['excel'] = Excel::load($path, function ($reader) {
$reader->sheet(0, function ($sheet) {
$sheet->setColumnFormat(["A" => "#"]);
});
})->toArray();

Actually the value you get is true. 1.98610012009011E+17 is the form of exponential value. But if you want get it as string form try this approach.
You should create a ValueBinder class.
// MyValueBinderClass
use PHPExcel_Cell;
use PHPExcel_Cell_DataType;
use PHPExcel_Cell_IValueBinder;
use PHPExcel_Cell_DefaultValueBinder;
class MyValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
{
public function bindValue(PHPExcel_Cell $cell, $value = null)
{
if (is_numeric($value))
{
$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
return true;
}
// else return default behavior
return parent::bindValue($cell, $value);
}
}
And then bind it to while you load the csv file:
$myValueBinder = new MyValueBinder;
$data = Excel::setValueBinder($myValueBinder)
->load($path)->toArray();
reference: http://www.maatwebsite.nl/laravel-excel/docs/import#formatting

It's out of the range for integer type .
use string for column type in DB
or cast it
$number= (float) $value;;

Related

Get enum value by name stored in a string in PHP

I want to get the value of an Enum in PHP by its name.
My enum is like:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
Status::from(2) can be used to get "REVIEWED", but how can I resolve the value from the name stored in a string ?
Well, it seems there is not any built-in solution in PHP. I've solve this with a custom function:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
public static function fromName(string $name): string
{
foreach (self::cases() as $status) {
if( $name === $status->name ){
return $status->value;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class );
}
}
Then, I simply use Status::fromName('ACTIVE') and get 1
If you want to mimic the from and tryFrom enum functions, you can also add:
public static function tryFromName(string $name): string|null
{
try {
return self::fromName($name);
} catch (\ValueError $error) {
return null;
}
}
You can use reflection for Backed case:
$reflection = new ReflectionEnumBackedCase(Status::class, 'REVIEWED');
$reflection->getBackingValue(); // 2
$reflection->getValue() // Status::REVIEWED if you need case object
Or enum reflection:
$reflection = new ReflectionEnum(Status::class);
$reflection->getCase('REVIEWED')->getValue()->value // 2
see also ReflectionEnumUnitCase
To get value from the name:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
print(Status::REVIEWED->value);
Enum documentation
I use a custom method too, but I return an enum.
The from method returns an enum, not a value. I think the fromName method should return an enum too. Then you have access to all methods of the enum. You don't need use another method - from.
public static function fromName(string $name): self
{
foreach (self::cases() as $status) {
if( $name === $status->name ){
return $status;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class );
}
public static function tryFromName(string $name): self|null
{
try {
return self::fromName($name);
} catch (\ValueError $error) {
return null;
}
}
The constant() function can return the value of a constant using a string variable.
This also applies to Enum class constants as mentioned in the basic enumeration section of the PHP Manual.
$name = 'REVIEWED';
$status = constant("Status::{$name}");
If anyone cares, I have created a library around that.
https://github.com/henzeb/enumhancer
Just add the trait to your enum
enum Status : int
{
use Henzeb\Enumhancer\Enhancers;
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
Status::get('ACTIVE');
Status::tryGet('ACTIVE');
You then don't have to use values at all. In that case you can also simply use from.
enum Status
{
use Henzeb\Enumhancer\Enhancers;
case ACTIVE;
case REVIEWED;
// ...
}
Status::from('ACTIVE')->key(); // returns 0
Status::tryFrom('Reviewed')->key(); // returns 1
It does so much more than that, but it defeats copying and pasting snippets around.

App\Models\ must return a relationship instance

I am trying to run some dynamic method calls based on the value of a database field. Some context: I have a model Anniversary and I want to display all upcoming anniversaries within the next x days. An anniversary has a date and a frequency. For example, monthly, quarterly, etc. Based on the frequency, I want to check for each anniversary if it is upcoming.
Here is my code so far:
$anniversaries = auth()->user()->anniversaries()->get();
$test = $anniversaries->filter(function ($anniversary) {
$method = Str::of($anniversary->frequency)->camel();
return ${$anniversary->$method}() == true;
});
dd($test);
The above works, when in the actual method I dd() something. But when returning true or false, I get the error:
App\Models\Anniversary::monthly must return a relationship instance
And in my model I just have a few methods like below, for testing:
public function monthly()
{
return true;
}
public function quarterly()
{
return false;
}
My only question is, I want to understand why I am getting this error and ofcourse any pointers in the right direction to get what I want to work. Thanks!
The following line creates an Illuminate\Support\Str object instead of a string. This causes the Method name must be a string error.
$method = Str::of($anniversary->frequency)->camel();
You can fix this by manually casting it to a string and invoking it directly:
$test = $anniversaries->filter(function ($anniversary) {
$method = (string) (Str::of($anniversary->frequency)->camel());
return $anniversary->$method() == true;
});
Throwing in my 2 cents for this as well. The Str::of(), which are "Fluent Strings" added in Laravel 7.x return an instance of Stringable:
https://laravel.com/api/8.x/Illuminate/Support/Stringable.html
For example:
dd(Str::of('monthly')->camel());
Illuminate\Support\Stringable {#3444
value: "monthly"
}
To get the value of this, as a string and not an object, you can cast it (as shown in MaartenDev's answer), or call the __toString() method:
dd(Str::of('monthly')->camel()->__toString());
"monthly"
In your code example, that would simply be:
$method = Str::of($anniversary->frequency)->camel()->__toString();
return $anniversary->{$method}() == true;
Alternatively, you can just use the Str::camel() function to bypass this Stringable class:
$method = Str::camel($anniversary->frequency);
return $anniversary->{$method}() == true;
https://laravel.com/docs/8.x/helpers#method-camel-case
Hope that helps clear up some confusion 😄
you have issue in this part ${$anniversary->$method}(). if you access a function like property laravel models thinks its relation function.
so replace with $anniversary->{$method}()
try this one
$anniversaries = auth()->user()->anniversaries()->get();
$test = $anniversaries->filter(function ($anniversary) {
$method = Str::of($anniversary->frequency)->camel();
return $anniversary->{$method}() == true;
});
dd($test);

Passing a variable to a ->each() function making the variable always = 0 php

One of the routes I'm making for my API in laravel requires me to pass a variable to a ->each() function.
This can be seen below:
public function by_location($zone_id)
{
$zone = Zone::where('id', $zone_id)->get()[0];
error_log($zone->id);
$exhibitors = Exhibitor::where('zone_id', $zone_id)->get();
$exhibitors->each(function($exhibitor, $zone)
{
error_log($zone->id);
$exhibitor['zone_info'] = $zone;
});
return response()->json($exhibitors);
}
This first error_log outputs '2', but with the second I get 'Trying to get property 'id' of non-object'.
Any help is apprecited!
You probably want to use $zone which you selected from database on first line.
Also if you want to change value of item you are iterating you have to use ->map() instead of ->each()
I changed ->get()[0] to ->first(). Never use ->get()[0]
public function by_location($zone_id)
{
$zone = Zone::where('id', $zone_id)->first();
error_log($zone->id);
$exhibitors = Exhibitor::where('zone_id', $zone_id)->get();
$exhibitors->map(function($exhibitor) use ($zone){
error_log($zone->id);
$exhibitor['zone_info'] = $zone;
return $exhibitor;
});
return response()->json($exhibitors);
}

Laravel Model Dynamic Attribute

I would like to ask how it's possible to create a dynamic attribute on the model class. Let's suppose I have a table structure like below code.
Schema::create('materials', function (Blueprint $table) {
$table->increments('id');
$table->string('sp_number');
$table->string('factory');
$table->text('dynamic_fields')->comment('All description of the material will saved as json');
$table->timestamps();
});
I have a column in my table structure named "dynamic_fields" that will hold a JSON string for the fields. An example of JSON structure below.
[
{
"name":"COLOR WAY",
"value":"ASDFF12"
},
{
"name":"DESCRIPTION",
"value":"agg2sd12"
},
{
"name":"REF NUM",
"value":"121312"
}
]
I want to access a field from my dynamic fields, like for example "COLOR WAY".
In my model I want to access the "COLOR WAY" field on the dynamic field like this way
$material->color_way;
Can anybody show me how to do it?
If you know that there will only be certain dynamic fields ahead of time, you could opt to create accessor methods for them. For example, you could add this to your model:
// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
'dynamic_fields' => 'array'
];
// ...
public function getColorWayAttribute()
{
foreach ($this->dynamic_fields as $field) {
if ($field['name'] === 'COLOR WAY') {
return $field['value'];
}
}
return null;
}
This will allow you to do:
$colorWay = $material->color_way;
Alternatively, if the combinations your dynamic_fields are not limited, there could be a large number of them or you want there to be more flexibility to be able to add more and have them accessible, you could override the getAttribute method of Laravel's model class.
// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
'dynamic_fields' => 'array'
];
// ...
public function getAttribute($key)
{
$attribute = parent::getAttribute($key);
if ($attribute === null && array_key_exists('dynamic_fields', $this->attributes)) {
foreach ($this->dynamic_fields as $dynamicField) {
$name = $dynamicField['name'];
if (str_replace(' ', '_', mb_strtolower($name)) === $key) {
return $dynamicField['value'];
}
}
}
return $attribute;
}
This approach calls Laravel's implementation of getAttribute which first checks if you have an actual attribute defined, or if you have an accessor defined for the attribute (like in my first suggestion), then checks if a method exists with that name on the base model class and then finally attempts to load a relation if you have one defined.
When each of those approaches fails (null is returned), we then check to see if there's a dynamic_fields attribute in the model. If there is, we loop through each of the dynamic fields (assuming your dynamic_fields is cast as an array), we then convert the name of the defined dynamic field to lowercase and replace spaces with underscores. We then finally check to see if the name we have just derived matches the key provided and if it does, we return the value. If it doesn't, the original $attribute will be returned, which will be null.
This would allow you to get any of your dynamic fields as if they were defined as attributes in the class.
$colorWay = $material->color_way;
$description = $material->description;
$refNum = $material->ref_num;
Please note: I have not tested this code, there could well be an issue or two present. Give it a try and see if it works for you. Also note that this will only work for getting dynamic fields, setting them will require overriding another method.
Try to use this code in your model:
protected $casts = [
'dynamic_fields' => 'array',
];
public function setAttribute($key, $value)
{
if (!$this->getOriginal($key)) {
$this->dynamic_fields[$key] = $value;
}
parent::setAttribute($key, $value);
}
public function getAttribute($key)
{
if (!$this->getOriginal($key)) {
return $this->dynamic_fields[$key]
}
parent::getAttribute($key);
}
In this example, you can get Dynamic Column form Dynamic Model. as well as its Models Relation too
1) first you have to define a table Scope in Model.
private $dynamicTable='';
public function scopeDefineTable($query,$tableName)
{
if( $tableName )
{
$this->dynamicTable= $tableName;
}
else
{
$this->dynamicTable= "deviceLogs_".date('n')."_".date('Y');
}
$query->from( $this->dynamicTable );
$this->table=$this->dynamicTable; # give dynamic table nam to this model.
}
public function scopeCustomSelect( $query ,$items=[])
{
$stu_class_col=['id as stu_class_id','std_id']; // Required else retional model will not retun data. here id and std_id is primary key and foreign key.
$stu_doc_col=['id as stu_doc_id','std_id'];// Required else retional model will not retun data. here id and std_id is primary key and foreign key.
foreach ( $items as $col)
{
if( Schema::hasColumn('student_information', $col ))
{
$stu_info_col[]= $col ;
}
elseif ( Schema::hasColumn('student_class',$col))
{
$stu_class_col[]= $col ;
}
elseif ( Schema::hasColumn('student_image',$col))
{
$stu_doc_col[]= $col ;
}
}
// converting array to string for bind column into with relation...
$stu_class_col_string = implode(',',$stu_class_col);
$stu_doc_col_string = implode(',',$stu_doc_col);
return $colQuery = $query->select($stu_info_col)
->with(["student_class:$stu_class_col_string", "studentImage:$stu_doc_col_string"]);
}
using this you can get data from Rational Model too...
from Controller
$studentInfo = Student::whereHas("student_class",function($q) use($req){
$q->where("std_session",$req->session_code);
$q ->where("std_class",$req->class_code);
$q ->where("std_section",$req->std_section); })
->customSelect($fields['dataList'])
->get();
here I am not using dynamic Model Scope. only Dynamic SustomSelect scope..

php native function to return value based on key

The title can be a bit confusing, but how can you process an array and return the value of the key based on a value given. This is basically for an array library that converts database meta-data into human-readable format.
Example:
$countries = array('US'=>'United States','MX'=>'Mexico');
The above array would be considered an array library. So when I do a query and in my results I only have the two country code, I would then need to convert that into human-readable format. Is there a function that if I send it the two country code it will return the human-readable format. This function would then need to be reusable with other array libraries. Example function:
function covert_to_human($key, $array_library)
This will return the value associated with $key in $array_library if it exists otherwise will return an optional $default if the key is not in the $array_library
function convert_to_human($key, $array_library, $default = null){
if (array_key_exists($key, $array_library)){
return $array_library[$key];
}
return $default;
}
If you want a supper easy way to define and maintain a lookup, you can wrap this concept in a class and use parse_ini_file to seed the data.
class Lookup{
protected $data;
public function __construct($iniFile){
$this->data = parse_ini_file($iniFile);
}
public function lookup($key, $default){
return isset($this->data[$key])?$this->data[$key]:$default;
}
}
To use you would author your lookup as
; Countries.ini
US = "United States of America"
MS = "Mexico"
CA = "Canada"
Then create an instance of and use your class
$countryLookup = new Lookup("Countries.ini");
echo $countryLookup->lookup("MX", "Unknown Country");
function convert_to_human($key, $library) {
return array_key_exists($key, $library) ? $library[$key] : false;
}

Categories