lundi 5 février 2018

laravel legacy database connection: normalize the columns+values received from DB

New to Laravel, be kind. :-)

I need to connect to a legacy database. I can not make changes to the structure or contents of that database, it is completely read-only.
Can I (and if so: how) create models so that I have "normalized" versions in my app?

E.g.

table 1:
  DB column           app model
  ---------------     -----------------------
- My_Title            title
- Some_Field1..10     (should not be retrieved)
- Label (int: 0,1,2)  label, lookup string from array ["labelA","labelB","labelC"]

table 2:
  DB column           app model
  ---------------     -----------------------
- The_Title           title
- ...

I can use $hidden, $casts and e.g. public function getLabelAsStringAttribute() + $appends to achieve some of it, but have not found a good / recommended way to :

  • "rename" columns in the app (not the database), e.g. my_title --> title
  • only retrieve certain columns; I only need a small subset of fields from the large database; e.g. only retrieve My_Title, Label.
  • completely replace column content (e.g. Label = 1 --> label = 'labelB')
    • related: $append adds it to ->toArray(), but not the collection objects themselves. That is indeed how it is documented, but I would like it to be part of the collection/model itself.

Would like this to work in Eloquent queries as well, e.g. App\Movie->where('title','Leon'), where the request to the database should still be querying for My_Title instead of title.

I have the feeling I can use Collection method transform, but it is not clear to me when/where/how to always apply that one when performing a Eloquent query. And/or create a Custom Collection? Like this example, where I could create a method normalize so that I can use \App\Movie->all()->normalize()->first()->title? But that seems to be part of building the query (vs processing the returned DB data) and would still leave me with the unwanted behavior of using the raw DB columns when building a query, e.g. \App\Movie->where("My_Title","Leon")->normalize()->first()->title.

Snippet of WIP:

// todo: enable e.g. 
// App\Movie->whereIn('label',['labelB','labelC'])
// which internally treats it as 
// App\Movie->whereIn('Label',[1,2])

// example of the final result of the query, with raw DB columns+values
// todo: don't even receive the unwanted columns, only receive "The_Title" and "Label"
$collection = collect([
    (Object) ["The_Title"=>"Leon","Some_Field1"=>"ignore me", "Some_Field2"=>"ignore me as well","Label"=>1],
    (Object) ["The_Title"=>"Dunkirk","Some_Field1"=>"ignore me","Label"=>2]
]);

// for every collection: 
// after data is loaded, transform it to a normalized version of the model
$collection->transform(function ($item, $key) { 
    return (Object) [
        "title"=>$item->The_Title, 
        "label"=>["labelA","labelB","labelC"][$item->Label]
    ]; 
})

// after that it is possible to treat it as a regular collection
$collection->first()->title

Suggestions?



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire