I have a Reminder model that has a sound_path column. I created an accessor for that column in the model but it's returning null and I doubled checked that the database has a value in that column. What am I doing wrong?
Note: Of course I can call $this->sound_path directly in soundPathUrl mutator without creating the accessor from the first place but I'm interested to know why if I called the accessor is not returning any value.
Reminder model
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Spatie\Translatable\HasTranslations;
class Reminder extends BaseModel
{
use HasFactory, SoftDeletes, HasTranslations;
public $translatable = [
'title__ml',
];
protected $casts = [
'available_days_for_reminder' => 'json',
'is_multiple_days_allowed' => 'boolean'
];
protected $appends = ['sound_path_url'];
/**
* Get the sound path
*
* #param string $value
* #return \Illuminate\Database\Eloquent\Casts\Attribute
*/
protected function soundPath(): Attribute
{
return Attribute::make(
get: fn ($value) => $value
);
}
/**
* Get sound path download URL
*
* #return \Illuminate\Database\Eloquent\Casts\Attribute
*/
protected function soundPathUrl(): Attribute
{
return new Attribute(
get: fn () => asset('storage/' . $this->soundPath),
);
}
}
Reminder controller
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\Reminder\ReminderCollection;
use App\Http\Resources\Reminder\ReminderResource;
use App\Models\Reminder;
use Exception;
use Illuminate\Http\Request;
class ReminderController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$reminders = Reminder::paginate(5);
return ReminderCollection::collection($reminders);
}
}
ReminderCollection API resource
namespace App\Http\Resources\Reminder;
use Illuminate\Http\Resources\Json\JsonResource;
class ReminderCollection extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title__ml,
'sound' => $this->sound_path_url
];
}
}
Screenshot of Response
At the arrow there should be the value of sound_path.
Your issue is that you are calling $this->soundPath instead of $this->sound_path in soundPathUrl method...
So, you should have this:
/**
* Get sound path download URL
*
* #return \Illuminate\Database\Eloquent\Casts\Attribute
*/
protected function soundPathUrl(): Attribute
{
return new Attribute(
get: fn () => asset('storage/' . $this->sound_path),
);
}
Check the documentation and you will see you still have to call your properties using snake_case.
It seems soundPath accessor does nothing, it returns the same value which seems empty. Where does soundPath value come from? First, make sure, soundPath itself has any value within that function.
Call soundPath as a function
protected function soundPathUrl(): Attribute
{
return new Attribute(
get: fn () => asset('storage/' . $this->soundPath()),
);
}
}
Related
I have a problem with my laravel 9:
Call to undefined method App\Models\Country::id()
I use the Laravel framework version 9.x for programming.
This is my model code:
class Country extends Model
{
use HasApiTokens, HasFactory, Notifiable, HasRoles;
protected $table = 'countries';
protected $fillable = [
'name',
'code'
];
}
This is my controller code:
<?php
namespace App\Http\Controllers;
use App\Models\Country;
use Illuminate\Http\Request;
use App\Services\LogWriter;
use Spatie\Permission\Models\Role;
class CountryController extends Controller
{
...
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\Country $country
* #return \Illuminate\Http\Response
*/
public function edit(Country $country)
{
return view('countries.edit', compact('country'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Models\Country $country
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Country $country)
{
$request->validate([
'name' => 'required|string|max:100',
'code' => 'required|string|max:2|unique:countries',
]);
$country->update($request->all());
message_set("Successful! Country information has been changed.", 'success', 5);
return redirect()->route('countries.index');
}
...
I dont know why I get this error and would be glad if I could get any help.
Lesson learned today, always check your error messages for the full information; assuming the problem was in the Controller can be right in a lot of cases, but Laravel's errors can also be triggered in a .blade.php view.
The problem was in the view edit.blade.php
"Check if you're calling ->id() in there"
In my Laravel 8 project I have a model called Campaign, my front-end though is build in Vue JS so needs to have some keys on a Campaign for contextual purposes, such as opening and closing a dropdown menu when looping over the elements, a database column isn't nessecery for this.
I'd like to add some default key/value pairs to my Campaign model, for example: dropdown_is_open and should have a default value of false.
I came across the default attributes for a model and tried adding this but cannot see my new key on the object, what am I missing?
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Campaign extends Model
{
use HasFactory, SoftDeletes;
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'campaigns';
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'campaign',
'template'
];
/**
* The model's default values for attributes.
*
* #var array
*/
protected $attributes = [
'dropdown_is_open' => false
];
}
Index function in controller:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$campaigns = Campaign::where('user_id', Auth::id())
->orderBy('created_at', 'desc')
->get();
if (!$campaigns) {
return response()->json([
'message' => "You have no campaigns"
], 404);
}
return response()->json([
'campaigns' => $campaigns
], 200);
}
I expect to see:
{
campaign: 'my campaign',
template: '',
dropdown_is_open: false <-- my key
}
Previously I was doing a foreach in my index function and adding the contextual keys on each item, but this would only show for the index function and I'd have to add it everywhere.
I hope something like below helps.
Change it from my_custom_field to dropdown_is_open key (and from getMyCustomFieldAttribute to getDropdownIsOpenAttribute method-name).
Custom attribute (or Accessor)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
protected $appends = ['my_custom_field'];
public function getMyCustomFieldAttribute()
{
return false;
}
}
The $appends in above is required only,
to ensure that my_custom_field is preset/cached, and even sent as JSON-Response.
Here are the codes:
This is the code in ProductFactory.php file where i defined the data to be generated for the Product
<?php
namespace Database\Factories;
use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ProductFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Product::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
$product_name = $this->faker->unique()->words($nb=4, $asText=true);
$slug = Str::slug($product_name);
return [
'name' => $product_name,
'slug' => $slug,
'short_description' => $this->faker->text(200),
'description' => $this->faker->text(500),
'regular_price' => $this->faker->numberBetween(10,500),
'SKU' => 'DIGI'.$this->faker->unique()->numberBetween(100, 500),
'stock_status' => 'instock',
'quantity' => $this->faker->numberBetween(100, 200),
'image'=> 'digit_'.$this->unique()->numberBetween(1,22).'.jpg',
'category_id' => $this->faker->numberBetween(1,5)
];
}
}
This is the code in CategoryFactory.php file where i defined the data to be generated for the Category.
<?php
namespace Database\Factories;
use App\Models\Category;
use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class CategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Category::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
$category_name = $this->faker->unique()->words($nb=2, $asText=true);
$slug = Str::slug($category_name);
return [
'name' => $category_name,
'slug' => $slug
//
];
}
}
This is the DatabaseSeeder.php where i called the two Models
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use \App\Models;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
\App\Models\Category::factory(6)->create();
\App\Models\Product::factory(22)->create();
}
}
I ran the command php artisan db:seed but i got above stated error I am stake now because everything seems fine
Use like this,
$category_name = $this->faker->unique()->numberBetween(1,20);
All your other unique calls use $this->faker->unique()... except this one:
'image'=> 'digit_'.$this->unique()->numberBetween(1,22).'.jpg',
Change it to use faker too:
'image'=> 'digit_'.$this->faker->unique()->numberBetween(1,22).'.jpg',
How can I seed my Comments table with comments.post_id as Foreign Key to post.id.
I have a Factory for the Comments table but not for the Post table.The Post table I populate manually so I can not link Factories.
I have a problem with adding a comment, because of the FK constraint. I insert a post.id manually, but don;t know how to let Laravel choose an id automatically.
Thanks in advance, Sam
CommentFactory
<?php
namespace Database\Factories;
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class CommentFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Comment::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
//
'post_id'=> 38,
'author' => $this->faker->name(),
'comment' => $this->faker->realText(150),
'approved' => 0,
];
}
}
CommentSeeder
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Comment;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class CommentSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
// factory(App\Comment::class, 25)->create();
Comment::factory()->count(rand(1,5))->create();
}
}
**Comment Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
use HasFactory;
protected $fillable = ['author','comment', 'post_id','approved'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
**
Post::all()->random()->id, always fetch any random post ID and assign it the comment.
<?php
namespace Database\Factories;
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class CommentFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Comment::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
//
'post_id'=> Post::all()->random()->id, <---- try this.
'author' => $this->faker->name(),
'comment' => $this->faker->realText(150),
'approved' => 0,
];
}
}
I used pluck() to create an array with all post.id
$posts = Post::all()->pluck('id')->toArray();
and used randomElement() to pick a random id as a post_id
$post_id = $this->faker->randomElement($posts);
Many thanks for the suggestions!
I am trying to set webhook url for each event I define.
So I have something like below.
UserModel
<?php
namespace app\Model\User;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Model\Device as DeviceModel;
/**
* Class User
* #package app\Model\User
*/
class User extends Authenticatable
{
use Notifiable;
/**
* #var string
*/
public $slackChannel;
/**
* Route notifications for the Nexmo channel.
*
* #return string
*/
public function routeNotificationForSlack() : string
{
if ( $this->slackChannel ){
return config('slack.channels.'.$this->slackChannel);
}
}
/**
* #param string $slackChannel
* #return object
*/
public function slackChannel(string $slackChannel) : object
{
$this->slackChannel = $slackChannel;
return $this;
}
}
Job
public function handle()
{
foreach( $this->users as $user ) {
$recipient = $user;
$user->slackChannel('order-requested')->notify(new OrderSubmittedByClient($this->order, $recipient));
}
}
config/slack
return [
'channels' => [
'order-requested' => 'https://hooks.slack.com/services/xxxxxx',
]
];
Even after I set $this->slackChannel to certain string, when it comes to routeNotificationForSlack, it returns null.
What am I doing wrong? I suspect jwt in the middleware, but will that matter?