I'm a bit stuck wondering what I'm doing wrong.
I'm trying to use the spatie/laravel-medialibrary & ebess/advanced-nova-media-library together with nova-flexible-content
In nova it works wonderful but can't get the image show in my blade. If anybody has any suggestions or know what I'm doing wrong.
Thanks in advance for your time :)
I followed there guide too: https://whitecube.github.io/nova-flexible-content/#/?id=usage-with-ebessadvanced-nova-media-library
My layout looks as follows:
<?php
namespace App\Nova\Flexible\Layouts;
use Whitecube\NovaFlexibleContent\Layouts\Layout;
use Spatie\MediaLibrary\HasMedia;
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary;
class Image extends Layout implements HasMedia
{
use HasMediaLibrary;
protected $name = 'image';
protected $title = 'Image';
public function fields()
{
return [
Images::make('Image', 'images'),
];
}
}
And my model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Whitecube\NovaFlexibleContent\Concerns\HasFlexible;
class Job extends Model implements HasMedia
{
use HasFactory;
use HasFlexible;
use InteractsWithMedia;
protected $guareded = [];
protected $casts = [
'publish_date' => 'date',
];
}
Controller:
public function show(Job $job)
{
return view('jobs.show', compact('job'));
}
Blade:
#foreach ($job->flexible('content') as $block)
{{ $block->getMedia('images') }}
#endforeach
composer:
"ebess/advanced-nova-media-library": "^4.0",
"spatie/laravel-medialibrary": "^10.0.0",
"whitecube/nova-flexible-content": "^1.0"
Following answer also can be found in the related Github issue.
I just solved my problem and it was that I'm casting the wrong class.
Let me explain a little bit more:
Before
protected $casts = [
'layouts' => \Whitecube\NovaFlexibleContent\Value\FlexibleCast::class
];
After
protected $casts = [
'layouts' => \App\Casts\MyFlexibleCast::class
];
Conclusion
If you're using custom layout classes like me, you need to cast the right class.
Related
I am working on a hybrid app build with Laravel and Vue.
I have a use case where not all users have certain relations. For example a client can have a Domain and Multiple Business Units.
Currently i have set it up like this:
<?php
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
use Spatie\MediaLibrary\HasMedia;
use Illuminate\Notifications\Notifiable;
use Lab404\Impersonate\Models\Impersonate;
use Spatie\MediaLibrary\InteractsWithMedia;
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements HasMedia
{
use Traits\BaseModelTrait;
use Traits\ActiveTrait;
use InteractsWithMedia;
use Impersonate;
use HasApiTokens;
use Notifiable;
use HasFactory;
protected $hidden = [
'password', 'remember_token',
];
protected $fillable = [
'name', 'email', 'password', 'avatar',
];
protected $casts = [
'settings' => AsArrayObject::class,
'is_admin' => 'boolean',
];
protected $with = [
'domain',
'BusinessUnits'
];
public function scopeAdmin($query)
{
return $query->where('is_admin', true);
}
public function scopeEmployee($query)
{
return $query->whereNull('domain_id');
}
public function scopeClient($query)
{
return $query->whereNotNull('domain_id');
}
public function BusinessUnits()
{
return $this->belongsToMany(BusinessUnit::class, 'users_business_units_pivot');
}
public function Domain()
{
return $this->belongsTo(Domain::class);
}
}
The "problem" with this approach is that for every request 2 queries are executed for each user. I want the relations eager loaded only if the "domain_id" is not null (scopeClient).
For normal "models" i can select per page what models should be loaded etc., but for the authenticated user this is not really possible as i know.
I think i am looking for something like this:
protected $with = [
(!$this->domain_id) ? 'domain' : null,
(!$this->domain_id) ? 'BusinessUnits' : null
];
This currently generates an error: "Constant expression contains invalid operations."
Any advice and or ideas to tackle this would be appreciated!
You can try using events:
// this code should be inside your model
public static function boot()
{
parent::boot();
self::retrieved(function($model){
if($model->domain_id !== null)
{
$model->load('domain', 'BusinessUnits');
}
});
}
and obviously, you have to remove those relations from $with
To get all the user that has domains, use whereHas()
$users = User::whereHas('Domain')->with(['Domain', 'BusinessUnits'])->get();
it will lauch 3 queries, one for the users, one for the domains and one for the business units.
OK so my User models uses webpatser/laravel-uuid. All migrations are using UUID.
So now my model looks like:
<?php
namespace App\Models;
use App\Models\Traits\Uuid;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
use Notifiable;
use Uuid;
public $incrementing = false;
public $timestamps = true;
protected $guarded = [
'uuid',
];
protected $keyType = 'string';
protected $primaryKey = 'uuid';
protected $table = 'users';
protected $dates = [
'created_at',
'updated_at',
];
protected $hidden = [
'password',
'remember_token',
];
public function setPasswordAttribute($password): void
{
$this->attributes['password'] = Hash::make($password);
}
}
I want to use database session driver. I created session table via php artisan session:table. All migrations are done. I obviously had to rename existing user_id column. I've changed it to user_uuid. I know it's not enough as I can't find the logic responsible for populating this db table. I guess it's somewhere in the vendor (Illuminate).
Where is the logic to populate my non-default session column?
Now each open the page gives:
So I know what's the issue, what's causing it, how to change it, but I don't know where to start. Thanks for any hints.
I think you would benefit of a custom session handler because the name of the column user_id is hardcoded into the addUserInformation() method.
Extend the existing DatabaseSessionHandler.php and replace the addUserInformation() method so it looks for the correct column name:
class DatabaseUuidSessionHandler extends DatabaseSessionHandler
{
protected function addUserInformation(&$payload)
{
if ($this->container->bound(Guard::class)) {
$payload['user_uuid'] = $this->userId();
}
return $this;
}
}
Register it in one of your service providers:
class SessionServiceProvider extends ServiceProvider
{
public function boot()
{
Session::extend('databaseUuid', function ($app) {
return new DatabaseUuidSessionHandler;
});
}
}
Finally update SESSION_DRIVER in your .env to use the newly created databaseUuid driver.
Remember that this is untested code and should only be used as a guideline of how this could work.
I am trying to show the related applications to abstract, I have used the code below but I am getting this error
Array to string conversion
My controller
public function show($A_ID){
$abstract = Project::find($A_ID);
// I believe the issue is caused by the line below but I am not sure what is wrong about it
$applications = Application::find($A_ID);
return view('Abstracts.show')->with('abstract', $abstract)
->with($applications);
}
EDIT: (add model v1.0 and v1.1)
My model (v1.0) which show the error of Array to string conversion
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Traits\HasCompositePrimaryKey;
class Application extends Model{
//Table name
protected $table = 'student_application';
//composite key
protected $primaryKey = array('A_ID', 'S_ID');
protected $fillable = ['S_Justification' ];
public $incrementing = false;}
My edited Model (V1.1)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCompositePrimaryKey;
class Application extends Model{
use HasCompositePrimaryKey;
//Table name
protected $table = 'student_application';
//composite key
protected $primaryKey = array('A_ID', 'S_ID');
protected $fillable = ['S_Justification' ];
public $incrementing = false;}
I want to note that the composite key is declared using this answer number two with currently 59 votes
For more information here is my view
#if (count($applications)>0)
#foreach ($applications as $application)
<tr>
<td><h5>{{$application->S_ID}}</h5></td>
</tr>
#endforeach
#else
<p> This project has no applications </p>
#endif
You are passing string to view.
return view('Abstracts.show')->with(['abstract'=> $abstract)];
give it a try.
Edit:
Or you can use like that.
with(array('order' => function($query)
Anyway you need to pass array in here. If you are just want to use ->with('abstract'); you need to add abstract function. For example:
public function deliveries() {
// this might be $this->hasOne... depends on what you need
return $this->hasMany('Abstracts', 'conditions', 'id')->where('foo', '!=', 'bar');
}
$applications is an object in your controller but you are accesing $applications as collection in your view file. You may try this:
$applications = Application::where('id', $A_ID)->get();
return view('Abstracts.show', compact('abstract', 'applications'));
I am having some trouble with route model binding my Eloquent subclass. The following code works fine:
$repo = new \App\Repositories\Eloquent\PluginRepository();
$plugin = $repo->findOrFail(1);
var_dump($plugin->type);
Output
object(App\PluginsTypes)#360 (26) {...}
But when I make a model bind, like this:
routes/web.php
Route::resource('plugins', 'PluginsController');
app/Http/Controllers/Admin/PluginsController.php
public function edit(PluginRepositoryInterface $plugin){
var_dump($plugin); // object(App\Repositories\Eloquent\PluginRepository)#345 (26) {...}
var_dump($plugin->id); // NULL
}
So the problem is, that it does not find the id passed in the route.
Addition code in Laravel project:
app/Plugins.php
<?php
namespace App;
class Plugins extends Model{
// My Eloquent Model
/**
* The foreignKey and ownerKey needs to be set, for the relation to work in subclass.
*/
public function type(){
return $this->belongsTo(PluginsTypes::class, 'plugin_type_id', 'id');
}
}
app/Repositories/SomeRepository.php
<?php
namespace App\Repositories;
use App\Abilities\HasParentModel;
class PluginsRepository extends Plugins{
protected $table = 'some_table';
use HasParentModel;
}
config/app.php
'providers' => [
...
App\Repositories\Providers\PluginRepositoryServiceProvider::class,
...
]
app/Repositories/Providers/PluginRepositoryServiceProvider.php
<?php
namespace App\Repositories\Providers;
use Illuminate\Support\ServiceProvider;
class PluginRepositoryServiceProvider extends ServiceProvider{
/**
* This registers the plugin repository - added in app/config/app.php
*/
public function register(){
// To change the data source, replace the concrete class name with another implementation
$this->app->bind(
'App\Repositories\Contracts\PluginRepositoryInterface',
'App\Repositories\Eloquent\PluginRepository'
);
}
}
Been using these resources:
HasParentModel Trait on GitHub
Extending Models in Eloquent
I found the answer in the docs (of course):
https://laravel.com/docs/5.6/routing#route-model-binding in the section Customizing The Resolution Logic
In my app/Repositories/Providers/PluginRepositoryServiceProvider.php i have added the following under my interface binding and it now works.
$this->app->router->bind('plugin', function ($value) {
return \App\Repositories\Eloquent\PluginRepository::where('id', $value)->first() ?? abort(404);
});
I will probably rename it, but it work like a charm :) Good day...
Trying to get Accessors in query builder but throwing error "Undefined property: stdClass::$shorcontent "
//controller
public function index(){
$articles = DB::table('articles')->paginate(10);
return view('articles.index', ['articles' => $articles], compact('articles'));
}
Here is the Model file with Accessors
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'user_id', 'content', 'live', 'post_on'
];
protected $guarded = ['id'];
public function getShortContentAttribute()
{
return substr($this->content,0, random_int(60, 150));
}
}
Here is the View
//article/index.blade.php View
<td class="col-md-6">{{ $article->shortcontent }} </td>
The same code working when i use eloquent instead of query builder, like this
public function index()
{
$articles = Article::paginate(10);
return view('articles.index', ['articles' => $articles], compact('articles'));
}
This answer is late and you might have found your solution, but hope it helps someone else.
Short answer, the DB facade doesn't have access to accessors and mutators defined in the model. Only objects made by instances of the model can have access to accessors and mutators.
I believe the issue here is that using the DB facade only creates the Query Builder without any reference to accessors or mutators you have set in the Article Model. DB facade only queries the database using the query builder and returns an object independent from the Article Model.
However, the Model facade will build a query builder but the instance of the object created will have access to accessors and mutators as it is an object instance of the Article Model class.
Check out this SO answer:
Difference between DB and Model facade
Accessors are only accessed once you attempt to retrieve the value of the attribute from the model instance, for example:
$article = Article::find(1);
$shortContent = $article->short_content;
This is explained further here
Thus if you wish to access accessors, then you would have to use the Model facade i.e. Article::paginate(10).
You are missing to append short_content attribute. Just add this
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'user_id', 'content', 'live', 'post_on'
];
protected $appends = ['short_content'];
protected $guarded = ['id'];
public function getShortContentAttribute()
{
return substr($this->content,0, random_int(60, 150));
}
}