Laravel Version: 7.26.1
PHP Version: 7.4.9
Database Driver & Version: MySql 8.0.21
Description:
Am I working on a project that mostly consists of belongsTo and hasMany relationships which I cache using a trick I learned a long time ago from this post Laravel Model Caching. Now the problem is when I run a test PHPUnit freezes or maybe takes to a long time to run a single test because I waited for an hour plus, but if I comment the the $touches property the test runs just fine. Now I cant comment out all the $touches property in all my models every time I want to test so my question is, what do I do, is it possible to turn it off during testing?
Steps To Reproduce:
Model
<?php
namespace App;
use App\Contracts\CacheableModelInterface;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Country extends Model implements CacheableModelInterface
{
use Searchable,
Concerns\HasSlug,
Concerns\HasCache,
Concerns\HasManyRegions,
Concerns\HasManyProvinces,
Concerns\HasManyLocalGovernmentAreas,
Concerns\HasManyCities,
Concerns\HasManyVillages;
/**
* The relationships that should be touched on save.
*
* #var array
*/
protected $touches = ['regions', 'provinces', 'localGovernmentAreas', 'cities', 'villages'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'longitude', 'latitude', 'iso_code', 'calling_code'
];
/**
* Get the indexable data array for the model.
*
* #return array
*/
public function toSearchableArray()
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
Repository
public function getRelationshipBelongingTo(string $name, string $relationship)
{
return ($this->model->where("name->".app()->getLocale(), $name)
->firstOrFail())
->{$relationship};
}
Controller
// CountryController.php
...
public function provinces(string $locale, string $name)
{
try {
$this->checkLocale($locale);
app()->setLocale($locale);
$provinces = $this->repository
->getRelationshipBelongingTo($name, 'cached_provinces');
return response()->json([
'success' => true,
'provinces' => new ProvinceCollection($provinces)
]);
} catch (ModelNotFoundException $exception) {
return response()->json([
'success' => false,
'message' => "No country named '{$name}' was found in the {$this->localeFullName($locale)} database."
]);
} catch (InvalidLocaleException $exception) {
return response()->json([
'success' => false,
'message' => $exception->getMessage()
]);
}
}
Test
/**
* #test
*/
public function can_return_provinces_belonging_to_country()
{
$country = $this->createCountry();
// Region is going to be needed in the factory when creating Province
// files so we need to have at least one present.
factory(\App\Region::class, 1)->create();
$provinces = $country->provinces()->saveMany(factory(\App\Province::class, 3)->make());
$response = $this->getJson($this->route."/{$country->name}/provinces");
$response->assertJsonStructure([
'success', 'provinces'
]);
$responseProvinces = $response->json('provinces');
$this->assertEquals($provinces->count(), collect($responseProvinces)->count());
$response->assertOk();
}
Related
Observer
class FileLogObserver
{
public function updated(FileLogs $fileLogs)
{
$fileChangeLogs = FileChangeLogs::firstWhere('fileId', $fileLogs->filedId);
if ( !empty($fileChangeLogs)) {
$fileChangeLogs->save([
'logDetails' => '1 file updated',
]);
}
}
}
Controller
class FileLogController extends Controller
{
public function update(Request $request,$id){
$validator = Validator::make(
$request->all(),
[
'orderId' => 'required|integer',
'fileId' => 'required|integer',
'status' => 'required|string'
]
);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
$data = FileLogs::find($id);
if($data){
$data->orderId=$request->orderId;
$data->fileId=$request->fileId;
$data->status=$request->status;
$data->update();
return response()->json(['status'=>'success','StatusCode'=> 200,'message'=>'Successfully Updated','data'=>$data]);
}
else{
return response()->json(['status'=>'Failed','message'=>'Update Failed'],400);
}
}
}
The created & retrieved methods are being properly triggered. However, the updated & deleted methods not triggered. Gone through many links & read that a reason can be becoz the update is not directly on the model. so, i tried like below in my controller. But update function is not working this method. I'm using Laravel-8 version. Any help is much appreciated.
$data = FileLogs::find($id);
if($data){
$data->update(['$data->orderId'=>'$request->orderId','$data->fileId'=>'$request->fileId','$data->status'=>'$request->status']);
you need to register those observer in App\Providers\EventServiceProvider
like
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
FileLogs::observe(FileLogObserver::class);
}
ref link https://laravel.com/docs/8.x/eloquent#observers
I have two tables news and images. These two tables have one-to-many relationship (one being news). I'm trying to make a factory on images, but right after I migrate with seed, the image saved to news directory but after one second it got deleted, and the path on the database returns news. I've read this question but laravel 8.4 (my current laravel project) uses phpfaker, so I guess it's now deprecated.
ImageFactory.php file
<?php
namespace Database\Factories;
use App\Models\Image;
use Illuminate\Database\Eloquent\Factories\Factory;
class ImageFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Image::class;
/**
* State dari gambarnya,
* pilih satu [news, packages, destinations]
*/
public function news()
{
return $this->state(function (array $attributes) {
return [
'role' => 'news',
];
});
}
public function packages()
{
return $this->state(function (array $attributes) {
return [
'role' => 'packages',
];
});
}
public function destinations()
{
return $this->state(function (array $attributes) {
return [
'role' => 'destinations',
];
});
}
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'path' => 'news' . '/' . $this->faker->image(storage_path('app/public/news'), 2000, 1500, null, false),
];
}
}
storage/app/public and storage/app/public/news has .gitignore file. I don't know if this is relevant or not, because my colleagues migrate the seed without any issues.
Referring to this comment, you just need to go to Images.php file on vendor PHPFaker and add these code
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
before $success = curl_exec($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;
im trying to run some additional code when a row is deleted using my Model. However the callback statis::deleted simply isn't being triggered.
Controller:
/**
* #param Website $website
* #param Request $request
* #return \Illuminate\Http\RedirectResponse
* #throws \Exception
*/
public function delete(Website $website, Request $request)
{
$id = $request->input('id-value');
WebsiteRedirects::query()->where(['website_id' => $website['id'], 'id' => $id])->delete();
Session::flash('message', [ 'is-success' => [ '1 Redirect has been deleted!' ] ]);
return back();
}
Model:
class WebsiteRedirects extends Model
{
protected $table = 'website_redirects';
protected $guarded = [];
public $timestamps = false;
protected static function boot()
{
parent::boot();
static::saved(function ($redirect) {
PlannerStatus::status('redirect', $redirect->website_id, 1);
});
static::deleted(function($redirect) {
dd('deleted');
PlannerStatus::status('redirect', $redirect->website_id, 1);
});
}
...
static::saved works fine, and I insert using query too.
WebsiteRedirects::query()->create(
[
'website_id' => $website->id,
'redirect_from' => $request->input('redirect-from'),
'redirect_to' => $request->input('redirect-to')
]
);
The event is not being called because you are not deleting the row via Eloquent. You are deleting the row directly, without fetching the result - therefor Eloquent can't run the deleted event.
You will have to fetch the model before deleting for the event to be triggered.
WebsiteRedirects::where(['website_id' => $website['id'], 'id' => $id])->first()->delete();
Add first() to retrieve the WebsiteRedirect before you run delete()
In your code
WebsiteRedirects::query()->where(['website_id' => $website['id'], 'id' => $id])
right before the delete() method, the instance of the object is Illuminate\Database\Eloquent\Builder not your model. wich will trigger the Eloquent delete (DB) not your model's one.
Normaly you would do something like:
$user = User::find($id);
$user->delete();
I am new to php development. Just for practicing I am creating a rest API following a video tutorial. I have followed each and every step but still unable to get the desired result. Below is the code
Employee Model
class Employee extends \yii\db\ActiveRecord
{
const SCENARIO_CREATE = 'create';
/**
* #inheritdoc
*/
public static function tableName()
{
return 'employee';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['emp_name', 'emp_email', 'emp_sal'], 'required'],
[['emp_name', 'emp_email', 'emp_sal'], 'string', 'max' => 100],
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['create'] = ['emp_name','emp_email', 'emp_sal'];
return $scenarios;
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'emp_name' => 'Emp Name',
'emp_email' => 'Emp Email',
'emp_sal' => 'Emp Sal',
];
}
}
Above the ID field is auto-increment
Employee Controller
public function actionCreateEmployee()
{
\Yii::$app->response->format= \yii\web\Response::FORMAT_JSON;
$employee = new Employee();
$employee-> scenario = Employee::SCENARIO_CREATE;
$employee->attributes = \Yii::$app->request->post();
if ($employee->validate())
{
return array('status'=> true, 'data' => 'Employee Created Sussessfully');
}
else
{
return array('status'=> false, 'data'=>$employee->getErrors());
}
//return array('status'=> true);
}
Now when I run the API in Postman. I got the following result.
Though I have entered all the required fields data still it gives me false status
Any help would be highly appreciated
You need to select x-www-form-urlencoded
The documentation says that the $_POST-parameter only gets filled on application/x-www-form-urlencoded or multipart/form-data and yii is probably using this.
An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.
from php.net
So I am working an a Laravel 5.2 API and I am working on creating the update method on a specific Model. The index, show($id) and store methods work fine so far. However I am getting the following error on my update method implementation:
BadMethodCallException in Macroable.php line 81:
Method save does not exist.
Here is the update method:
public function update($id, CreateZoneRequest $request)
{
$zones = Zone::where('_id', '=', $id) -> get();
if(sizeof($zones) == 0){
return response()->json(['message' =>'That zone number is invalid', 'code' => 404], 404);
}
$description = $request->get('description');
$zones ->description = $description;
$zones ->save();
return response() -> json(['message' => 'The zone has been updated'], 200);
}
Here is the CreateZoneRequest code:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class CreateZoneRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return
[
'description' => 'required',
];
}
public function response (array $errors){
return response() -> json(['message' => 'You are missing a required field', 'code' => 422], 422);
}
}
Here is the index method (for reference). This one is working without problems:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Zone;
use Illuminate\Support\Facades\Input;
use App\Http\Requests\CreateZoneRequest;
class ZoneController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$zones = Zone::all();
if(sizeof($zones) == 0){
return response()->json(['message' =>'There are no zones', 'code' => 404], 404);
}
return response() -> json(['data' => $zones], 200);
}
Here is the detailed Error Message when trying to use PUT on this endpoint api/v1/zones/1?description=Blah
When you use get() method you get a Collection object. You should use first() method to get model object.
Read more here: https://laravel.com/docs/5.2/eloquent#retrieving-single-models
You have to get a single instance of Zone model using first(), then you can use save() or update() methods
public function update($id, CreateZoneRequest $request)
{
$zones = Zone::where('_id', '=', $id) -> first();
if(sizeof($zones) == 0){
return response()->json(['message' =>'That zone number is invalid', 'code' => 404], 404);
}
$description = $request->get('description');
$zones ->description = $description;
$zones ->save();
return response() -> json(['message' => 'The zone has been updated'], 200);
}