Yii2 how can an model attribute is modified after load method? (like the afterFind method) - yii2

I have an attribute of the model which should be modified after it's loaded from the database.
I could extend the afterFind method, which could the convert the varchar value to a php array. So it works find.
But when the model is loaded I have no idea how to convert that varchar to the php array.
I have tried with rules but does not works:
[['languages'], 'each', 'rule' => ['string']],
or this one
[['languages'], 'safe'],
So this one works afterFind:
public function afterFind()
{
$this->languages = $this->convertToPHPArray($this->languages);
parent::afterFind();
}
By the way I have tried to extend the init or the __constructor method with this conversation, but no success, after load method the languages attribute is still a string instead of a php array.

If I understood your question, I think that you could use a property in the model:
public class Model {
public function getLanguagesArray()
{
return $this->convertToPHPArray($this->languages);
}
}
Then, use it:
$arr = $model->languagesArray;

Related

How to convert Laravel DB data into a suitable JSON form to use it in vuejs

The attributes of laravel modal are named using underscore (_), for example :
first_name
but attributes of javascript objects are named with camelCase:
{ firstName: "..." }
And this presents a conflict, is there a solution to resolve it ?
Try to use Laravel eloquent resource pattern will do that for You.
Check this helpful documentation.
https://laravel.com/docs/8.x/eloquent-resources
Like Zrelli Mjdi mentioned it's done with Resource Collections.
I did not find a way to let this resources transform the result recursively for nested JSON-Objects, so I created a middleware (see the github-gist) for this, which should take a rather heavy toll on performance. So use it sparsely.
I'd use this middleware only temporary if your frontend demands camel-case properties. In the long run I'd modify my migrations to use camel-case fieldnames. This should, according to this reddit-thread, be possible and won't affect performance like my middleware.
Edit: The code in the gist had a bug which is now fixed.
This is about how it's done with Resource-Collections and non-nested JSON-Results:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class MyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'userId' => $this->user_id,
'createdAt' => $this->created_at,
];
}
}
in the controller:
public function myControllerMethod(Request $request)
{
// ...
return MyResource::collection($logs)
}

Why ths php dynamic object class creation is not working?

I am trying to create a class (working as factory class) in my Zend Expressive APP as follows:
declare(strict_types=1);
namespace App\Install\Factory;
use App\Install\Model as Models;
use App\Install\Abstracts\AttributeInterface;
class AttributeEntityFactory{
public static function create($type1 ='Attribute') : AttributeInterface
{
$resolvedClass = "Models\\$type1";
$resolvedClass1 = 'Models\\'.$type1;
//return new $resolvedClass();
//return new $resolvedClass1();
return new Models\Attribute();
}
}
The above code works perfectly for me. However, if try to use any of the other two return statements it shows
Class 'Models\Attribute' not found
How can I achieve dynamic instantiation?
The attribute class code is as follows:
namespace App\Install\Model;
use App\Install\Abstracts\AttributeInterface;
class Attribute implements AttributeInterface
{
protected $attribute;
public function setAttribute($attribute)
{
$this->attribute = $attribute;
}
public function getAttribute()
{
return $this->attribute;
}
}
My PHP version is:
PHP 7.2.13 (cli) (built: Dec 14 2018 04:20:16) ( NTS )
you may need to pass in the full namespace?
"App\Install\Model\" . $type1;
and more...
the model Attribute you have is in the namespace App\Install\Model, and the object you are trying to create is from Models\\ . $type1
maybe you need to change Models to Model
Personally, I would avoid such factory implementation because of several reasons:
It involves magic.
Less predictable code.
Harder to read for both humans and IDE's (E.g: PHPStorm would not find the usages of Attribute class in such code when you need to find it)
Harder to analyze using static analyzers
Instead, I would rewrite this to a more explicit factory, even if I had dozens of different classes in App\Install\Model namespace:
<?php declare(strict_types=1);
namespace App\Install\Factory;
use App\Install\Model as Models;
class AttributeEntityFactory
{
public static function create($type = 'Attribute') : AttributeInterface
{
switch ($type) {
case 'Attribute':
return new Models\Attribute();
case 'SomethingElse':
return new Models\SomethingElse();
default:
throw new \InvalidArgumentException(
sprintf('An unknown type %s requested from %s', $type, __METHOD__)
);
}
}
}
As a rule of thumb:
Never compose classnames / namespaces using strings concatenated with variables / parameters / constants whatever.
Never call methods in such way, too.
You'll thank me when your application/business/codebase grows enough.

Typescript class with default values, how to parse JSON to this

I have a class of type A.
This class has several properties, let's call them prop1, prop2 and prop3.
When I'm calling an API, that returns a JSON string representing the object, some properties might be omitted if they are null. Further down the road, however, this object is used to construct a form dynamically (using Formik, but that's unrelated).
This framework expects all properties to be there, and some will be visible dynamically depending on other properties.
So my question, how can I parse a JSON response to my custom class, keeping default values in case properties are omitted in the API response?
What I've tried was:
static getCustomer(id) {
return fetch(process.env.MD_API_URL + 'customers/' + id, { mode: 'cors' })
.then(response => {
let cust = new Customer();
return response.json().then(x => cust = JSON.parse(x));
}).catch(error => {
return error;
});
}
But this returns undefined. Must be doing something wrong...
since typescript is not actually compiled but translated into javascript so all the javascript rules apply.
Therefore deserializing json wont actually create a new instance of the class in question but gives you an object you can "call" Customer during design time.
you could however create an object and then assign the json values like this:
export class Customer {
public id: number;
public name: string;
// your stuff here
public myDefaultProp: string = "default value";
public constructor(init?: Partial<Customer>) {
Object.assign(this, init);
}
}
your return then would look like this:
return response.json().then(x => new Customer(JSON.parse(x)));
added an example https://stackblitz.com/edit/typescript-16wlmg
This essentially just a matter of determining what to do in order to create an instance of a class, and map the properties of a JSON response towards your custom class, and there could be many different ways to solve this,
But I think (Factory function) is appropriate approach for this kind of task.

Laravel: decode JSON within Eloquent

I need to JSON decode a certain column in my Eloquent query. Is there a way to do this without breaking all apart?
So far I have this.
public function index()
{
return Offer::all();
}
Use an accessor on the model:
public function getColumnNameAttribute($value) {
return json_decode($value);
}
or use attribute casting to tell Laravel to do it automatically:
protected $casts = [
'column_name' => 'array',
];
The array cast type is particularly useful when working with columns that are stored as serialized JSON.
Note that you may have to stop json_encodeing your data if you use casts, as Laravel will now do that step automatically as well.

Where is defined the according type for the JSON output in Zend Framework 2?

I activated the JsonStrategy in a ZF2 application and can get JSON output now using AcceptableViewModelSelector Controller Plugin.
It works only with the HTTP Request parameter Accept containing application/json.
Where is application/json defined as proper value for JSON output? (How) Can I define and use foo/bar instead?
Take a look here:
Zend\View\Strategy\JsonStrategy;
You can implement your own custom strategy in the same manner no problem. Much cleaner than hard coding into the controller as it can be reused.
Directly in the definition array of the accept criteria:
class SomeController extends AbstractActionController
{
protected $acceptCriteria = array(
'Zend\View\Model\JsonModel' => array(
'application/json', // <-- here
),
'Zend\View\Model\FeedModel' => array(
'application/rss+xml',
),
);
public function apiAction()
{
$viewModel = $this->acceptableViewModelSelector($this->acceptCriteria);
// Potentially vary execution based on model returned
if ($viewModel instanceof JsonModel) {
// ...
}
}
}