I write a code using laravel 8 and i want to create CRUD Testing for all model so i can called it in every test case, for example I Have Operator Test that extends TestCase (crud testing master) ref : crud test, this is my Operator Test looks like,..
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class OperatorTest extends TestCase
{
use RefreshDatabase, WithFaker;
public function test_user_can_update_an_operator()
{
$this->setBaseRoute('master.operator');
$this->setBaseModel('App\Models\Operator');
$this->signIn();
$this->attributes = [
'username' => 'test update',
'level' => 1,
'category_id' => 1,
'password' => 'password'
];
$this->update($this->attributes);
}
}
and this is my TestCase.php looks like,...
<?php
namespace Tests;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use App\Models\Operator;
use Illuminate\Foundation\Testing\WithFaker;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
use RefreshDatabase;
protected $base_route = null;
protected $base_model = null;
protected function signIn($user = null)
{
$user = $user ?? Operator::factory()->create();
$this->actingAs($user);
return $this;
}
protected function setBaseRoute($route)
{
$this->base_route = $route;
}
protected function setBaseModel($model)
{
$this->base_model = $model;
}
protected function update($attributes = [], $model = '', $route = '')
{
$this->withoutExceptionHandling();
$route = $this->base_route ? "{$this->base_route}.update" : $route;
$model = $this->base_model ?? $model;
$model = create($model);
if (! auth()->user()) {
$this->expectException(\Illuminate\Auth\AuthenticationException::class);
}
$response = $this->patchJson(route($route, $model->id), $attributes);
tap($model->fresh(), function ($model) use ($attributes) {
collect($attributes)->each(function($value, $key) use ($model) {
$this->assertEquals($value, $model[$key]);
});
});
return $response;
}
}
after that when I tun php artisan test, i got an error like this :
anything worng in my codes ? i used laravel 8.
You need to initialize the model first and then call the model factory.
The create function is undefined at line 64.
Instead of
$model = create($model);
Use bellow code
$model = app()->make($model)
$model = $model::factory()->create();
More information on app()->make() and factory.
Related
I have been trying to create a point system, so after much effort i am getting this error which i could not figure out how to solve it because this is my first time working so deep
I have checked code but couldn't pinpoint the error
call to undefined app\models\User:id()
point model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Point extends Model
{
use HasFactory;
const TABLE = 'points';
protected $table = self::TABLE;
protected $fillable = [
'id', 'amount', 'message', 'current_points'
];
public function pointable(): MorphTo
{
return $this->morphTo();
}
public function getCurrentPoints(Model $pointable)
{
$currentPoints = Point::where('pointable_id', $pointable->id())
->where('pointable_type', $pointable->getMorphClass())
->orderBy('created_at', 'desc')
->pluck('current_points')->first();
if($currentPoints){
$currentPoints = 0;
}
return $currentPoints;
}
public function addAwards(Model $pointable, $amount, $message)
{
$award = new Static();
$award->amount = $amount;
$award->current_points = $this->getCurrentPoints($pointable) + $amount;
$award->message = $message
$pointable->awards()->save($award);
return $award;
}
}
pointable model
<?php
namespace App\Models;
interface pointable
{
public function awards();
public function countAwards();
public function addPoints($amount, $message);
}
hasPoints Traits
<?php
namespace App\Traits;
use App\Models\Point;
trait HasPoints
{
public function awards($amount = null)
{
return $this->morphMany(Point::class, 'pointable')
->orderBy('created_at', 'desc')
->take($amount);
}
public function countAwards()
{
return $this->awards()->count();
}
public function currentPoints()
{
return (new Point())->getCurrentPoints($this);
}
public function addPoints($amount, $message)
{
return (new Point())->addAwards($this, $amount, $message);
}
}
AwardPointLItener
?php
namespace App\Listeners;
use App\Events\ReplyWasCreated;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class AwardPointForNewReply
{
public function handle(ReplyWasCreated $event)
{
$amount = config('points.rewards.new_reply');
$message = 'User Created A New Reply';
$author = $event->reply->user;
$author->addPoints($amount, $message);
}
}
ReplyEvent
<?php
namespace App\Events;
use App\Models\Reply as Replyers;
use Illuminate\Queue\SerializesModels;
class ReplyWasCreated
{
use SerializesModels;
public $reply;
public function __construct(Replyers $reply)
{
$this->reply = $reply;
}
}
livewire reply componet
use Livewire\Component;
use App\Models\Reply as Replys;
class Reply extends Component
{
public $thread;
public $username;
public $reply_text;
public $replyCommentId = NULL;
protected $rules = [
'reply_text' => 'required'
];
public function mount(Thread $thread)
{
$this->thread = $thread;
}
public function render()
{
$replys = Replys::whereNull('parent_id')
->with('replies')
->with('user')
->where('thread_id', $this->thread->id)->paginate()->withQueryString();
return view('livewire.thread.reply',[
'replys' => $replys,
]);
}
public function save_reply()
{
$this->validate();
$replyevent = Replys::create([
'thread_id' => $this->thread->id,
'user_id' => auth()->user()->id,
'reply_text' => $this->reply_text,
'parent_id' => $this->replyCommentId
]);
event(new ReplyWasCreated($replyevent));
// $this->username = '';
$this->reply_text = '';
$this->replyCommentId = NULL;
}
public function deleteReply($id)
{
$reply = Replys::FindOrFail($id);
$reply->delete();
}
public function replys($replyId)
{
$this->replyCommentId = $replyId;
}
}
To get the id of a model, you simply access its id property. There is no id() method.
$currentPoints = Point::where('pointable_id', $pointable->id)
In my Laravel 8 project, I have this action class:
<?php
namespace App\Actions\Content;
use Illuminate\Support\Facades\Config;
class FixUriAction
{
public function __invoke(string $uri)
{
if (preg_match('/^https?:\/\//i', $uri)) {
return $uri;
}
return '/' . Config::get('current_lang')->code . '/' . $uri;
}
}
I want to write unit tests for this class, now I have this code in my test file:
<?php
namespace Tests\Unit\Actions\Content;
use App\Actions\Content\FixUriAction;
use App\Models\Settings\Lang;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Config;
use PHPUnit\Framework\TestCase;
class FixUriActionTest extends TestCase
{
use DatabaseTransactions;
protected Lang $lang;
protected FixUriAction $action;
public function setUp(): void
{
parent::setUp();
$this->action = new FixUriAction();
$this->lang = Lang::factory()->make();
Config::set('current_lang', $this->lang);
}
public function testShouldPrefixUriWithLangCode(): void
{
$uri = '/a-test-uri';
$expectation = '/' . $this->lang->code . $uri;
$result = ($this->action)($uri);
$this->assertEquals($expectation, $result);
}
}
In my LangFactory I have this code:
<?php
namespace Database\Factories;
use App\Models\Settings\Lang;
use Illuminate\Database\Eloquent\Factories\Factory;
class LangFactory extends Factory
{
protected $model = Lang::class;
public function definition()
{
return [
'name' => $this->faker->country,
'code' => $this->faker->languageCode,
];
}
}
When I run phpunit tests/Unit/Actions/Content/FixUriActionTest.php command it says:
There was 1 error:
1) Tests\Unit\Actions\Content\FixUriActionTest::testShouldPrefixUriWithLangCode
InvalidArgumentException: Unknown formatter "country"
I use PHPUnit 9.5.6 with PHP 7.4, Laravel 8.49
What I miss?
try in this way
<?php
namespace Database\Factories;
use App\Models\Settings\Lang;
use Illuminate\Database\Eloquent\Factories\Factory;
class LangFactory extends Factory
{
protected $model = Lang::class;
public function definition()
{
return [
'name' => $this->faker->country(),
'code' => $this->faker->languageCode(),
];
}
}
it should work
It seems you're using fakerphp library, which doesn't have the country formatter. Instead you can use the country code (2 letters or 3 letters). Check here for further details.
https://fakerphp.github.io/formatters/miscellaneous/#countrycode
when i call the feature test i get the following error:Call to undefined method App\Services\TrelloCardService::_downloadCardsFromBoard().I don't understand the reason for the error
I wrote the following service:
namespace App\Services;
use App\Services\Api\TrelloCardAPIService;
class TrelloCardService
{
protected $trelloCardApiService;
public function __construct(TrelloCardAPIService $trelloCardApiService)
{
$this->trelloCardApiService = $trelloCardApiService;
}
}
then a service that calls the API:
<?php
namespace App\Services\Api;
use App\Traits\CardTrait;
use Unirest\Request;
class TrelloCardAPIService
{
public function call(string $url) {
$headers = array('Accept' => 'application/json');
$query = array('key' => env('TRELLO_KEY'), 'token' => env('TRELLO_TOKEN'));
$r = Request::get($url, $headers, $query);
return $r->body;
}
public function _downloadCardsFromBoard() {
echo "API downloadCards!\n";
$url = TRELLO_API_BASE_URL . "/boards/".TRELLO_BOARDS_SPRINT."/cards";
$res = $this->call($url);
return $res;
}
}
then I wrote the test feature:
namespace Tests\Feature;
use App\Services\Api\TrelloCardAPIService;
use App\Services\TrelloCardService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\File;
use Tests\TestCase;
class trelloCardTest extends TestCase
{
public function test_mock_card()
{
$cards = json_decode(File::get("tests/test_data/cards.json"),FALSE);
$mock = $this->mock(TrelloCardAPIService::class, function ($mock) use ($cards) {
$mock->shouldReceive('_downloadCardsFromBoard')
->once()
->andReturn($cards);
});
//here I print the var mock if I do the DD
$mockedTrelloCardService = new TrelloCardService($mock);
$data = $mockedTrelloCardService->_downloadCardsFromBoard();//fail this
dd($data);//I would like to print $cards
}
}
give me following error:
Error: Call to undefined method App\Services\TrelloCardService::_downloadCardsFromBoard()
Here, I have setuo CRUD table with laravel, vuetify and vue . I could successfull create and read data from the database. But, for some reason my update and delete are not working. I am getting error like:
{message: "Creating default object from empty value", exception: "ErrorException",…}
exception: "ErrorException"
file: "C:\WinNMP\WWW\chillibiz\app\Sys\Http\Controllers\StageController.php"
line: 53
message: "Creating default object from empty value"
trace: [{file: "C:\WinNMP\WWW\chillibiz\app\Sys\Http\Controllers\StageController.php", line: 53,…},…]
My code are here:
StageController.php
<?php
namespace App\Sys\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Sys\Model\Stage;
class StageController extends Controller
{
public function index(Request $request)
{
$per_page = $request->per_page ? $request->per_page : 5;
$sort_by = $request->sort_by;
$order_by = $request->order_by;
return response()->json(['stages' => Stage::orderBy($sort_by, $order_by)->paginate($per_page)],200);
}
public function store(Request $request)
{
$uuid = Str::uuid()->toString();
$stage= Stage::create([
'id' => $uuid,
'code' =>$request->code,
'name' =>$request->name,
'description' =>$request->description,
]);
return response()->json(['stage'=>$stage],200);
}
public function show($id)
{
$stages = Stage::where('code','LIKE', "%$id%")->orWhere('name','LIKE', "%$id%")->orWhere('description', 'LIKE', "%$id%")->paginate();
return response()->json(['stages' => $stages],200);
}
public function update(Request $request, $id)
{
$stage = Stage::find($id);
$stage->code = $request->code; //line 53
$stage->name = $request->name;
$stage->description = $request->description;
$stage->save();
return response()->json(['stage'=>$stage], 200);
}
public function destroy($id)
{
$stage = Stage::where('id', $id)->delete();
return response()->json(['stage'=> $stage],200);
}
public function deleteAll(Request $request){
Stage::whereIn('id', $request->stages)->delete();
return response()->json(['message', 'Records Deleted Successfully'], 200);
}
}
Stage.php
<?php
namespace App\Sys\Model;
use Illuminate\Database\Eloquent\Model;
class Stage extends Model
{
protected $guarded = [];
}
I just found they you are using uuid as id not increment. that why you get error like that:
to solve your problem you need to add the field to your model;
<?php
namespace App\Sys\Model;
use Illuminate\Database\Eloquent\Model;
class Stage extends Model
{
public $incrementing = false;
protected $keyType = 'string';
protected $guarded = [];
}
I hope this time you can solve your problem. happy coding.
Edit you can read docs for more info
I want to send email with pdf attachment in SendReport job.
<?php
namespace App\Jobs;
use App\Models\Site;
use App\Models\User;
use App\Repositories\PositionRepository;
use Barryvdh\DomPDF\Facade as Pdf;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Mail;
class SendReport extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
private $email = '';
private $period = '';
private $siteId = -1;
public function __construct(string $email, string $period, int $siteId)
{
$this->email = $email;
$this->period = $period;
$this->siteId = $siteId;
}
public function handle()
{
$site = Site::find($this->siteId);
$period = $this->period;
$repo = new PositionRepository();
list($searchRequests, $positions) = $repo->getTodayPositions($site);
$pdf = Pdf::loadView(
'report.report',
compact('site', 'period', 'searchRequests', 'positions')
);
$content = $pdf->output('report.pdf');
$user = User::where('email', $this->email)->first();
Mail::queue(
'emails.report',
[
'user' => $user,
],
function ($m) use ($user, $content) {
$m->to($user->email, $user->name)
->cc(env('ADMIN_EMAIL'))
->subject('Report');
$m->attachData($content, 'Report.pdf', [
'mime' => 'application/pdf',
]);
}
);
}
}
But it shows me ReflectionException in Container.php line 738: Class does not exist. If I save pdf to file and then use attach($pathToFile, ...) instead of attachData($pdfContent, ...) it works. Or if I don't pass $content to Closure, all is ok, message is sent.
Mail::queue(
'emails.report',
[
'user' => $user,
],
function ($m) use ($user) {
$m->to($user->email, $user->name)
->cc(env('ADMIN_EMAIL'))
->subject('Report');
}
);
Maybe pdf size is too big? I want to use exactly attachData() instead of attach($pathToFile, ...).