Intervention Image with Laravel Resource API - php

Is it possible to return a image created on the fly with Laravel API Resources without saving it?
Tried in controller
$sum = Product::where('slug', $product)->first();
$img = Image::make('image_path')->resize(400, 400);
$img->text(name, 205, 138, function($font) {
$font->file('fonts/BostonHeavy.woff');
$font->size(42);
$font->color('#ffffff');
$font->align('center');
$font->valign('top');
});
return (new ProductResource($sum))->foo($img);
Laravel API Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
protected $image;
public function foo($value){
$this->image = $value;
return $this;
}
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'image' => $this->image,
];
}
}
what gets returned
{
"data": {
"id": 1,
"name": "Such a pickle",
"image": {
"encoded": "",
"mime": "image/jpeg",
"dirname": null,
"basename": null,
"extension": null,
"filename": null
}
}
}
This obviously is not working in the docs it says to use return $img->response('jpg'); which on it's own works but I want to added it to the response instead of doing two get requests.

From what I understand you want to return something you can use inside a src attribute in an img tag. Try this:
$imgBase64 = (string) $img->encode('data-url');
return (new ProductResource($sum))->foo($imgBase64);
Then, use that string in an img tag with the appropriate syntax:
<img src="data:image/jpeg;base64, <<yourEncodedStringHere>>" />

Related

Laravel Export: Attempt to read property "second_key" on null

I need to export data with Laravel Export, but the code return ErrorException: Attempt to read property "second_key" on null.
My code:
<?php
namespace App\Admin\Extensions;
use Encore\Admin\Grid\Exporters\ExcelExporter;
use Maatwebsite\Excel\Facades\Excel;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class DataExporter extends ExcelExporter implements FromQuery, WithMapping, ShouldAutoSize
{
protected $fileName = 'Export Data.xlsx';
public function headings(): array
{
return [
'ID',
'Title',
'Status',
'Gender',
'Data',
];
}
public function map($data): array
{
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$data->json_data->second_key, // <-- Here's the error
];
}
}
I've tried to check using this:
print_r(json_encode($data->json_data));
and this is the result:
{
"id": 282,
"second_key": "second_value",
"third_key": "6200",
"fourth_key": "0000",
"fifth_key": 28
}
I've also done this:
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$data->json_data //Without "second_key"
];
and the excel cell returns the same result:
{
"id": 282,
"second_key": "second_value",
"third_key": "6200",
"fourth_key": "0000",
"fifth_key": 28
}
As #dbf said in the comment section, I have to handle empty rows. I have checked several times in the database, and maybe I missed that one blank row.
Anyway, this is how I handle those values:
if (!isset($data->json_data->second_key)) {
$second_key = '-';
} else {
$second_key = $data->json_data->second_key;
}
return [
$data->id,
$data->title,
$data->status,
$data->gender,
$second_key
];

Laravel format time

I have some problems with getting time on my app. I'm using laravel api to send informations to my React app.
I have controller like:
public function index(){
$user = auth()->user();
$servers = Server::where('clientid', $user->id)
->orderBy('id', 'desc')
->take(10)
->get();
if ($user) {
$reposne['result'] = true;
$reposne['servers'] = $servers;
} else {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $reposne;
}
And it's successfuly returns what I need, like:
{
"result": true,
"servers": [
{
"id": 2512,
"clientid": 4,
"boxid": 23,
"ipid": 60,
"vazido": 1584355476,
"created_at": null,
"updated_at": null,
"status": "Active"
}
]
}
But as you see there is column vazido that is actyally giving a timestamp. How can I make this time to actual human format?
You can add a $casts attribute in your Server Model and Laravel will handle the rest for you.
Sever Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Server extends Model
{
protected $casts = [
'vazido' => 'datetime:Y-m-d',
];
}
In your model, You can use Eloquent Mutators to formate the date as following.
public function getVazidoAttribute($value)
{
return $value->format('Y-m-d');
}
By default, timestamps are formatted as 'Y-m-d H:i:s'.
I think your column type is int or string. So you can change the column type to timestamp or datetime.
$table->datetime('vazido')->change();
Or you can use mutator to convert the number to the datetime format, add this method to your Server Model:
public function getVazidoAttribute($value) {
return \Carbon\Carbon::createFromTimestamp($value)->format('Y-m-d H:i:s');
}

Laravel - Store JSON response in SQL database (via Guzzle)

First post! New to php & Laravel, figured I'd learn by creating a test project. I've been following Laracasts for guidance but run into issues.
What I'm looking to achieve:
Utilise Guzzle to call for an API
Store response into mySQL database
Setup a route for this
Setup a schedule so the controller runs once a day on schedule (I can start a new thread if need be)
I've got a controller setup for the Guzzle & storing data. I've got a database created which works as intended. The route I'm unsure about though on what exactly needs to be done so I'm struggling here on how to actually run the controller and store the data in the database.
I'd appreciate if anyone could review my code if I've done anything wrong, and give some guidance on routes in context of this.
Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
class DataController extends Controller
{
public function index()
{
$client = new Client(['base_uri' => 'https://api.ratings.food.gov.uk/ratings']);
$response = $client->request('GET', [
'headers' => [
'x-api-version' => '2',
'Accept' => 'application/json'
]
]);
$mydata = json_decode($response->getBody()->getContents(), true);
$object = new Object();
$object->ratingId = $mydata->ratingId;
$object->ratingName = $mydata->ratingName;
$object->ratingKey = $mydata->ratingKey;
$object->ratingKeyName = $mydata->ratingKeyName;
$object->schemeTypeId = $mydata->schemeTypeId;
$object->save();
Requests::insert($object);
}
}
?>
Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRatingsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('ratings', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
$table->integer('ratingId');
$table->string('ratingName');
$table->string('ratingKey');
$table->string('ratingKeyName');
$table->integer('schemeTypeId');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('ratings');
}
}
API JSON Response Example
{
"ratings": [
{
"ratingId": 12,
"ratingName": "5",
"ratingKey": "fhrs_5_en-gb",
"ratingKeyName": "5",
"schemeTypeId": 1,
"links": [
{
"rel": "self",
"href": "http://api.ratings.food.gov.uk/ratings/12"
}
]
},
{
"ratingId": 11,
"ratingName": "4",
"ratingKey": "fhrs_4_en-gb",
"ratingKeyName": "4",
"schemeTypeId": 1,
"links": [
{
"rel": "self",
"href": "http://api.ratings.food.gov.uk/ratings/11"
}
]
},
{
"ratingId": 10,
"ratingName": "3",
"ratingKey": "fhrs_3_en-gb",
"ratingKeyName": "3",
"schemeTypeId": 1,
"links": [
{
"rel": "self",
"href": "http://api.ratings.food.gov.uk/ratings/10"
}
]
}
}
You should leverage the power of Eloquent ORM. I've found some issues in your code. You need to remove unnecessary lines that you have written there in order to create an object. Considering that you have created the columns with same names as returned by the API response, and considering that your model name is Rating and it should be, here are my suggestions:
Your controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
use App\Rating;
class DataController extends Controller
{
public function index()
{
$client = new Client(['base_uri' => 'https://api.ratings.food.gov.uk/ratings']);
$response = $client->request('GET', [
'headers' => [
'x-api-version' => '2',
'Accept' => 'application/json'
]
]);
$mydata = json_decode($response->getBody()->getContents(), true);
/* You don't need to create an object as you are already parsing the response as an array, so remove below lines */
// $object = new Object();
// $object->ratingId = $mydata->ratingId;
// $object->ratingName = $mydata->ratingName;
// $object->ratingKey = $mydata->ratingKey;
// $object->ratingKeyName = $mydata->ratingKeyName;
// $object->schemeTypeId = $mydata->schemeTypeId;
// $object->save();
Rating::create($mydata);
}
}
And add make the columns fillable in your Rating model by adding a protected static $fillable property to your Rating model:
protected static $fillable = ['ratingId', 'ratingName', 'ratingKeyName', 'schemeTypeId'];
If above solution isn't the one you liked, then you need to either treat $mydata as an array, i.e. do $mydata['ratingId'] to get ratingId, not $mydata->ratingId or remove true argument from json_decode() to parse the response as an object, not an array.

Laravel how use value instead of full object with join in eloquent model

When I call eloquent:
$user = User::where('idUser', 1)->with(['privilege'])->first()->toArray();
It gives me:
{
"idUser": 1,
"name": "UserName",
"email": "UserName#gmail.com",
"image": "https://image.com",
"createdAt": "2019-05-07 15:43:47",
"privilege": {
"idPrivilege": 1,
"name": "user"
}
}
When I call Eloquent:
$user = User::where('idUser', 1)->with(['privilege:name'])->first()->toArray();
Element privilege in json is set to null, but when I call:
$user = User::where('idUser', 1)->with(['privilege:idPrivilege,name'])->first()->toArray();
It is as same as first call. How can I set element privilege to f.e. user (I just want a simple value instead of the full object of Privilege)?
I can use something like:
$user['privilege'] = $user['privilege']['name'];
But this one does not look so nice!
Using resource:
public function toArray($request)
{
return [
'idUser' => $this->idUser,
'name' => $this->name,
'email' => $this->email,
'privilege' => $this->privilege['name'],
'createdAt' => $this->created_at,
];
}
In controller:
$user = User::where('idUser', 1)->with('privilege')->first();
return UserResource::make($user);
Gives:
{
"data": {
"idUser": 1,
"name": "UserName",
"email": "UserName#gmail.com",
"privilege": "user",
"createdAt": "2019-05-07 15:43:47"
}
}
How can i just return object instead of data{object} ?
Try without the backets:
$user = User::where('idUser', $id)->with('privilege:name')->first()->toArray();
or this:
$user = User
::where('idUser', $id)
->with(['privilege' => function($query) {
return $query->select('name');
}])
->first()
->toArray();
But then, you could customize the response to return to your view using API Resources. With this, you can have many different resources to use on the same elements and format the response to any of your needs.
As stated in HCK's answer, you could use
$user = User
::where('idUser', $id)
->with(['privilege' => function($query) {
return $query->select('name');
}])
->first()
->toArray();
To get what you need. Now, if you are already using API Resources, and want to remove the outter data object, you can add the following in your AppServiceProvider boot method:
use Illuminate\Http\Resources\Json\Resource;
class AppServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* #return void
*/
public function boot()
{
Resource::withoutWrapping(); // With this, your resources won't have the
// outter data wrapping
}
}
Just take a look at the docs!

Laravel 5.5 Eloquent - Article::find returning null

I have two files,
CommentTransformer
And
ImageTransformer
In the first file, CommentTransformer, I can retrieve which Article it belongs to by doing this:
$article = Article::find($comment->article_id);
I'm doing the same exact thing in my ImageTransformer, but it returns null. Even if instead of using Article::find($image->article_id) I use Article::find(1) I still get a null result!
Here's the full code:
namespace App\Transformers;
use App\Article;
use App\User;
use App\Image;
use League\Fractal\TransformerAbstract;
class ImageTransformer extends TransformerAbstract
{
/**
* A Fractal transformer.
*
* #return array
*/
public function transform(Image $image)
{
$user = User::findOrFail($image->user_id);
$article = Article::find($image->article_id);
// $userArticle = User::find($article->user_id);
return [
'id' => (int) $image->id,
'original_filename' => $image->original_filename,
'filename' => $image->filename,
'size' => (int) $image->size,
'path' => url('/') . "/" . $image->path . '/' . $image->filename,
'posted_by_username' => $user->name,
'article' => $article //if I call $article->id it returns "Trying to get property of non-object" as it is, it returns null
];
}
}
This is the response:
{
"data": [
{
"id": 1,
"original_filename": "ptd.jpg",
"filename": "f11bbe288649e76ec3b694890160abf930601aed.jpeg",
"size": 103297,
"path": "http:\/\/192.168.1.85:1299\/uploads\/f11bbe288649e76ec3b694890160abf930601aed.jpeg",
"posted_by_username": "josh beck",
"article": null
}
]
}
I assume that this one returns null because findOrFail() would throw an
exception:
$article = Article::find($image->article_id);
If this returns null, it means there is no Article with the specified ID. You can check ID with dd($image->article_id);
Also, you can just load the data by using load() method:
$image->load(['user', 'article']);

Categories