Member Since 2 Years Ago
2,530 experience to go until the next level!
In case you were wondering, you earn Laracasts experience when you:
Earned once you have completed your first Laracasts lesson.
Earned once you have earned your first 1000 experience points.
Earned when you have been with Laracasts for 1 year.
Earned when you have been with Laracasts for 2 years.
Earned when you have been with Laracasts for 3 years.
Earned when you have been with Laracasts for 4 years.
Earned when you have been with Laracasts for 5 years.
Earned when at least one Laracasts series has been fully completed.
Earned after your first post on the Laracasts forum.
Earned once 100 Laracasts lessons have been completed.
Earned once you receive your first "Best Reply" award on the Laracasts forum.
Earned if you are a paying Laracasts subscriber.
Earned if you have a lifetime subscription to Laracasts.
Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.
Earned once you have achieved 500 forum replies.
Earned once your experience points passes 100,000.
Earned once your experience points hits 10,000.
Earned once 1000 Laracasts lessons have been completed.
Earned once your "Best Reply" award count is 100 or more.
Earned once your experience points passes 1 million.
Earned once your experience points ranks in the top 50 of all Laracasts users.
Earned once your experience points ranks in the top 10 of all Laracasts users.
Replied to Laravel: Custom Language Files Not Being Loaded For Package
I would like to point out that as you can see above in the jsonPaths
array that the custom language files for other packages gets loaded without separately registering them...
Started a new Conversation Laravel: Custom Language Files Not Being Loaded For Package
Hi,
I am using the package mailcoach by spatie to host my own email marketing. However, I would like to edit the language files. Regarding to the Laravel docs this can be done by:
So, for example, if you need to override the English translation strings in messages.php for a package named skyrim/hearthfire, you should place a language file at: resources/lang/vendor/hearthfire/en/messages.php
So, in my case the package is called spatie/laravel-mailcoach
which would resolve in resources/lang/vendor/laravel-mailcoach/de/messages.php
. However, there are two problems I face.
When I publish the language files from the package the folder is called mailcoach
instead of laravel-mailcoach
. However, I have tried both (at the same time) and neither of my language files were loaded. How can this be?
I want to load a .json
file instead of a .php
file. I assume that it will work as described above. Which would mean the correct path file would be resources/lang/vendor/laravel-mailcoach/de.json
. Is this correct?
If 2
is correct, why is Laravel still loading the wrong language file?
I dug a little into the Illuminate\Translation\Translator
file and added a dd($this)
for the get
method which will retrieve the correct translation for the given key. What I found is the following:
Illuminate\Translation\Translator {#604 ▼
#loader: Illuminate\Translation\FileLoader {#603 ▼
#files: Illuminate\Filesystem\Filesystem {#92}
#path: "Programmieren/MyWebsiteProject/resources/lang"
#jsonPaths: array:4 [▼
0 => "Programmieren/MyWebsiteProject/vendor/arcanedev/log-viewer/translations"
1 => "Programmieren/MyWebsiteProject/vendor/llaski/nova-scheduled-jobs/src/../resources/lang"
2 => "Programmieren/MyWebsiteProject/resources/lang/vendor/nova-scheduled-jobs"
3 => "Programmieren/MyWebsiteProject/vendor/spatie/laravel-mailcoach/src/../resources/lang/"
]
#hints: array:3 [▼
"log-viewer" => "Programmieren/MyWebsiteProject/vendor/arcanedev/log-viewer/translations"
"NovaScheduledJobs" => "Programmieren/MyWebsiteProject/vendor/llaski/nova-scheduled-jobs/src/../resources/lang"
"validationRules" => "Programmieren/MyWebsiteProject/vendor/spatie/laravel-validation-rules/src/../resources/lang/"
]
}
#locale: "de"
#fallback: "en"
#loaded: array:1 [▼
"*" => array:1 [▼
"*" => array:1 [▼
"de" => array:403 [▼
...
// my translations
...
]
]
]
]
#selector: null
#parsed: []
}
As you can see in the jsonPaths
array, the mailcoach
language files are not the one in my resources/lang/vendor/laravel-mailcoach
or resources/lang/vendor/mailcoach
folder but rather the original one.
Can anybody explain me why this happens and not the files under resources/lang/vendor
are being loaded?
What is interesting is the fact that when I add the line $this->loadJsonTranslationsFrom(resource_path() . '/lang/vendor/mailcoach');
to my boot
function in my AppServiceProvider
the jsonPaths
array above gets one more item Programmieren/MyWebsiteProject/resources/lang/vendor/mailcoach
which is the correct one.
And then my customized language files are also being used but the original one are still being loaded. How can this be?
Besides that I would like to know why I even have to register my custom language file? This is not a normal behavior... I would like to find the bug/problem.
Kind regards
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
You forgot php artisan horizon:install
. But yes, I agree with you! It has to do something with the config because now it is working... strange.
I will add each config line separately to debug and see which line causes the problem.
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
On request of Laravel I have now reproduced the problem in a new repo: https://github.com/FrazeColder/laravel-issue-36613
I get the same result when running php artisan horizon
and I did nothing else then installing horizon and edited my config files. I have included the .env
file now because of configs.
Here you can follow the issue on laravel/framework https://github.com/laravel/framework/issues/36613
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
Here it is:
[2021-03-16 11:18:19] local.ERROR: Trying to access array offset on value of type null {"exception":"[object] (ErrorException(code: 0): Trying to access array offset on value of type null at /vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php:156)
[stacktrace]
#0 /vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php(156): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'Trying to acces...', '/vendor...', 156, Array)
#1 /vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php(138): Illuminate\Queue\QueueManager->resolve('mailcoach-redis')
#2 /vendor/laravel/framework/src/Illuminate/Queue/Worker.php(145): Illuminate\Queue\QueueManager->connection('mailcoach-redis')
#3 /vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(117): Illuminate\Queue\Worker->daemon('mailcoach-redis', 'mailcoach', Object(Illuminate\Queue\WorkerOptions))
#4 /vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(101): Illuminate\Queue\Console\WorkCommand->runWorker('mailcoach-redis', 'mailcoach')
#5 /vendor/laravel/horizon/src/Console/WorkCommand.php(51): Illuminate\Queue\Console\WorkCommand->handle()
#6 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Laravel\Horizon\Console\WorkCommand->handle()
#7 /vendor/laravel/framework/src/Illuminate/Container/Util.php(40): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#8 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#9 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#10 /vendor/laravel/framework/src/Illuminate/Container/Container.php(610): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#11 /vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\Container\Container->call(Array)
#12 /vendor/symfony/console/Command/Command.php(256): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#13 /vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#14 /vendor/symfony/console/Application.php(971): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /vendor/symfony/console/Application.php(290): Symfony\Component\Console\Application->doRunCommand(Object(Laravel\Horizon\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /vendor/symfony/console/Application.php(166): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 /vendor/laravel/framework/src/Illuminate/Console/Application.php(92): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#18 /vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#19 /artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#20 {main}
"}
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
How can I get the full stacktrace from the terminal?
This is all what the terminal outputs:
ErrorException
Trying to access array offset on value of type null
at vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php:156
152▕ protected function resolve($name)
153▕ {
154▕ $config = $this->getConfig($name);
155▕
➜ 156▕ return $this->getConnector($config['driver'])
157▕ ->connect($config)
158▕ ->setConnectionName($name);
159▕ }
160▕
+19 vendor frames
20 artisan:37
Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
No worries! I am very happy about every single answer.
I get this a few seconds after I execute php artisan horizon
and I get this error multiple times!
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
No, there was no process queued or working in the background. I tried both, but sadly still the same result
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
Thanks for your reply, but sadly also not working...
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
Sadly also not working... I also have run composer dump-autoload
, same result...
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
Yes, I did. Here is my file:
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => env('DB_CONNECTION', 'mysql'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mailcoach-redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 11 * 60,
'block_for' => null,
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_CACHE_DB', 1),
],
],
];
Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
I have, but no changes.. still getting the error because phpredis
is the default value for database.php
Started a new Conversation Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis
Hi,
I am about to setup Redis
and Laravel Horizon
. Although I have set up everything correctly (I assume) I get a very weird error. Laravel
tells me that it is Trying to access array offset on value of type null
at vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php:156
The line 156
is the first return line:
/**
* Resolve a queue connection.
*
* @param string $name
* @return \Illuminate\Contracts\Queue\Queue
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
return $this->getConnector($config['driver']) // <-- This line
->connect($config)
->setConnectionName($name);
}
So, I assume Laravel
cannot access $config['driver']
. But when I do a dd
of $config
I get the following:
array:5 [
"driver" => "redis"
"connection" => "default"
"queue" => "default"
"retry_after" => 90
"block_for" => null
]
So, it is impossible that driver
is empty because as you can see driver
is set to redis
. Do you guys have any idea why Laravel
cannot access array offset on value of type null
?
I have installed phpredis
, a Redis database
and also Laravel Horizon
. When I try to access my /horizon
I get the same error as above.
phpredis
is installed correctly. I have added extension=redis.so
to my php.ini
and when I execute php -r "if (new Redis() == true){ echo \"\r\n OK \r\n\"; }"
in my command line I also get OK
. So, it cannot be phpredis
.
My Redis database
is also working:
$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
And my configs are also correct. This is my .env
(just some entries):
APP_ENV=local
APP_DEBUG=true
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=password
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Here is my config/queue.php
:
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same
| syntax for every one. Here you may define a default connection.
|
*/
'default' => env('QUEUE_CONNECTION', 'sync'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'your-queue-name'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish.
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];
My config/horizon.php
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Horizon Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Horizon will be accessible from. If this
| setting is null, Horizon will reside under the same domain as the
| application. Otherwise, this value will serve as the subdomain.
|
*/
'domain' => env('HORIZEN_DOMAIN', null),
/*
|--------------------------------------------------------------------------
| Horizon Path
|--------------------------------------------------------------------------
|
| This is the URI path where Horizon will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('HORIZEN_PATH', 'horizon'),
/*
|--------------------------------------------------------------------------
| Horizon Redis Connection
|--------------------------------------------------------------------------
|
| This is the name of the Redis connection where Horizon will store the
| meta information required for it to function. It includes the list
| of supervisors, failed jobs, job metrics, and other information.
|
*/
'use' => 'default',
/*
|--------------------------------------------------------------------------
| Horizon Redis Prefix
|--------------------------------------------------------------------------
|
| This prefix will be used when storing all Horizon data in Redis. You
| may modify the prefix when you are running multiple installations
| of Horizon on the same server so that they don't have problems.
|
*/
'prefix' => env(
'HORIZON_PREFIX',
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
),
/*
|--------------------------------------------------------------------------
| Horizon Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will get attached onto each Horizon route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Queue Wait Time Thresholds
|--------------------------------------------------------------------------
|
| This option allows you to configure when the LongWaitDetected event
| will be fired. Every connection / queue combination may have its
| own, unique threshold (in seconds) before this event is fired.
|
*/
'waits' => [
'redis:default' => 60,
],
/*
|--------------------------------------------------------------------------
| Job Trimming Times
|--------------------------------------------------------------------------
|
| Here you can configure for how long (in minutes) you desire Horizon to
| persist the recent and failed jobs. Typically, recent jobs are kept
| for one hour while all failed jobs are stored for an entire week.
|
*/
'trim' => [
'recent' => 60,
'pending' => 60,
'completed' => 60,
'recent_failed' => 10080,
'failed' => 10080,
'monitored' => 10080,
],
/*
|--------------------------------------------------------------------------
| Metrics
|--------------------------------------------------------------------------
|
| Here you can configure how many snapshots should be kept to display in
| the metrics graph. This will get used in combination with Horizon's
| `horizon:snapshot` schedule to define how long to retain metrics.
|
*/
'metrics' => [
'trim_snapshots' => [
'job' => 24,
'queue' => 24,
],
],
/*
|--------------------------------------------------------------------------
| Fast Termination
|--------------------------------------------------------------------------
|
| When this option is enabled, Horizon's "terminate" command will not
| wait on all of the workers to terminate unless the --wait option
| is provided. Fast termination can shorten deployment delay by
| allowing a new instance of Horizon to start while the last
| instance will continue to terminate each of its workers.
|
*/
'fast_termination' => false,
/*
|--------------------------------------------------------------------------
| Memory Limit (MB)
|--------------------------------------------------------------------------
|
| This value describes the maximum amount of memory the Horizon master
| supervisor may consume before it is terminated and restarted. For
| configuring these limits on your workers, see the next section.
|
*/
'memory_limit' => 64,
/*
|--------------------------------------------------------------------------
| Queue Worker Configuration
|--------------------------------------------------------------------------
|
| Here you may define the queue worker settings used by your application
| in all environments. These supervisors and settings handle all your
| queued jobs and will be provisioned by Horizon during deployment.
|
*/
'defaults' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'maxProcesses' => 1,
'memory' => 128,
'tries' => 1,
'nice' => 0,
],
],
'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'simple',
'processes' => 10,
'tries' => 2,
'timeout' => 60 * 60,
],
'mailcoach-general' => [
'connection' => 'mailcoach-redis',
'queue' => ['mailcoach', 'mailcoach-feedback', 'send-mail'],
'balance' => 'auto',
'processes' => 10,
'tries' => 2,
'timeout' => 60 * 60,
],
'mailcoach-heavy' => [
'connection' => 'mailcoach-redis',
'queue' => ['send-campaign'],
'balance' => 'auto',
'processes' => 3,
'tries' => 1,
'timeout' => 60 * 60,
],
],
'local' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'simple',
'processes' => 10,
'tries' => 2,
'timeout' => 60 * 60,
],
'mailcoach-general' => [
'connection' => 'mailcoach-redis',
'queue' => ['mailcoach', 'mailcoach-feedback', 'send-mail'],
'balance' => 'auto',
'processes' => 10,
'tries' => 2,
'timeout' => 60 * 60,
],
'mailcoach-heavy' => [
'connection' => 'mailcoach-redis',
'queue' => ['send-campaign'],
'balance' => 'auto',
'processes' => 3,
'tries' => 1,
'timeout' => 60 * 60,
],
],
],
];
Anyone has an idea why I get this error?
I am working on php 7.4.16
, 10.5.6-MariaDB
, redis-cli 6.2.1
and on Laravel Framework 8.32.1
. So, everything is on the newest version.
I would appreciate any kind of help! Kind regards
Replied to Laravel + Vue Server Side Rendering
@martinbean Is there any possibility to speed up those processes as well? Because My page needs 1,4s till the first content is painted, 2,7s to be able to interact with the page and 3,6s till my page is fully loaded and that is all because my Vue components need such a long time to display.
When load my page, the first content I see is my footer because my footer is not coded in Vue, just simple HTML. Why do my components needs such a long time? Is it maybe because I pass the data to my Vue components via my blade instead of doing an axios request? Because I pass them through my blade the HTML document is very big.
Or any other idea how I can speed up the page speed? (Caching is not really an option because I have a very dynamic website. All I can cache, I do cache, like images, etc.)
Started a new Conversation Laravel + Vue Server Side Rendering
Hi,
I have a Laravel application which is using some vue components inside my blades. So, not all of my blade content is coded in vue just certain thinks. However, I would like to implement Server Side Rendering to speed up my webpage.
There is a package from spatie called laravel-server-side-rendering. As it seems to me I have to create a App.vue file which contains all of my vue components which will be rendered by the server. And this App.vue is going to be bind to a div inside my blade. Is this the way how it works and did I get it right?
Because if so, that is bad for me. Because I my vue components are not in a row. There is one vue component, then some standard blade html content, again a vue component, again some standard blade stuff and again a vue component.
Is it possible to have server side rendering only for the vue components itself? Because then I would be able to keep my current hierarchy in my blades.
Kind regards
Replied to Laravel Nova: How To Create A Custom Field And Its Crud Methods?
I am very sorry.. but have your read the text? I want to implement a text editor.
Started a new Conversation Laravel Nova: How To Create A Custom Field And Its Crud Methods?
Hi,
I want to create a custom field for my Laravel Nova application. Thanks to Laracast I already figured out how I can to this (here). But I don't know how to edit the create, update and delete method and sadly I also haven't found anything about it...
The reason why I need to edit those functions is because I am using spatie/media-library to take care about my images I upload. Now I want to add a textfield editor to my Laravel Nova Recourse which can also handle images. However, those images should be added to the spatie/media-library and when updating or deleting the recourse, the image should of course also be deleted...
I have implemented such kind of function in my front end already with the quill editor. Users have the possibility to create comments and upload images as well within the comments. The images are send as base64 strings within my text field to my controller which then is taking care about saving the base64 image to my spatie/media-library.
Any idea how I can do the same with Laravel Nova?
Kind regards and thanks!
Started a new Conversation Spatie Media Library Is Adding Media When Passing A Eloquent Query Result To A Blade
Hi,
I have a written a project in which I am using the Spatie Medialibrary. Right now I am writing tests for my code but I am facing a very weird problem. In my tests I want to check if the view really does contain the variables I have passed them and if they are identical. How do I do that? I am using $this->assertViewHas('products', User::productsPaginated($user))
.
assertViewHas
is comparing if the view data with the key products
is identical to the result of User::productsPaginated($user)
, if yes the test passes. But in my case the test fails. And why is the test failing? Because when passing my products to the blade in my show
function in my controller, somehow the Spatie Medialibrary is adding the relation media
and filling up the variable mediaCollections
. But I don't know why and I really don't know why mediaRelations
is containing 4 items...
Here you can check the difference between my original value of of User::productsPaginated($user)
and the actual result of the passed variable to my blade: https://www.diffchecker.com/6pL3h0Ej. On the left side you can see the original result of User::productsPaginated($user)
and on the right site you can see the data of the passed variable to the blade.
Does anyone has an idea why Spatie Medialibrary is doing that or where this is coming from and how I can fix that?
If you take a look at the show()
function in my controller you can see that the data I pass are from the User::productsPaginated($user)
function. But I have also added a comment. Because if I dump the data of $products
in my show()
function in my controller there is NO media
relation added or a filled mediaCollections
array. This means, the relationship add items of the array has to be added when passing the $products
to the blade... But why?
Does anyone has an idea?
Whats also very strange: The mediaCollections
array contains the lines where I define my media collections. But why do they are defined two times? I have only 2 media collections but 4 items in my mediaCollections
array?
My test:
/** @test */
public function a_not_logged_in_user_user_requests_his_own_user_profile()
{
$user = User::factory()->create();
$this->actingAs($user);
Auth::logout();
$product = Product::factory(['user_id' => $user->id])->create(['page_status_id' => PageStatus::getIdByStatus('publish')]);
$response = $this->get(route('user.show', $user->name));
dd(array(
$this->getResponseData($response, 'product'),
User::productsPaginated($user)
));
$response->assertViewHas('userView', User::userStripped($user));
$response->assertViewHas('product', User::productsPaginated($user));
}
My User Controller which is passing the data to the blade (Important: please take a look at the comment):
public function show(User $user)
{
$products = User::productsPaginated($user);
$userView = User::userStripped($user);
//When dumping the $products here there is NO 'media' relationship added and the 'mediaCollections' array is also empty!
//dd($products)
return view('pages.userDashboard')->with([
'userView' => $userView,
'products' => $products
]);
}
My products model which is providing the productsPaginated function:
class Product extends Model implements HasMedia
{
use InteractsWithMedia;
use Actionable;
use MorphToComments;
use HasFactory;
/**
* @Protected_variables
*/
protected $table = 'products';
protected $guarded = ['id'];
protected $with = ['user', 'comments.likes', 'comments.likesByAuthUser', 'comments.reportedByAuthUser', 'comments.children', 'comments'];
protected $hidden = [
'performance_index',
'rank_index',
'link_clicks_general',
'link_clicks_details',
'rel_link_click_details_views'
];
protected $casts = [
'start_date' => 'datetime',
'end_date' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
protected $appends = [
'actions',
'isLikedByAuthUser',
'isDislikedByAuthUser',
'sumLikes',
'isMarkedAuthUser',
'isReportedByAuthUser',
'isExpiredByAuthUser',
'isSubscribedByAuthUser',
'image',
'imageFull',
'strippedContent'
];
/**
* @Public_variables
*/
/**
* @Relationships
*/
public function user()
{
return $this->belongsTo('App\Models\User');
}
public function dispatchCountry()
{
return $this->belongsTo('App\Models\DispatchCountry');
}
public function supplier()
{
return $this->belongsTo('App\Models\Supplier');
}
public function productType()
{
return $this->belongsTo('App\Models\ProductType');
}
public function pageStatus()
{
return $this->belongsTo('App\Models\PageStatus');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'products_categories');
}
public function likes()
{
return $this->belongsToMany('App\Models\User', 'products_likes', 'product_id', 'user_id')->withPivot('value')->withTimestamps();
}
public function marks()
{
return $this->belongsToMany('App\Models\User', 'products_marks', 'product_id', 'user_id')->withTimestamps();
}
public function expires()
{
return $this->belongsToMany('App\Models\User', 'products_expires', 'product_id', 'user_id')->withTimestamps();
}
public function reports()
{
return $this->belongsToMany('App\Models\User', 'products_reports', 'product_id', 'user_id')->withTimestamps();
}
public function deleteRequest()
{
return $this->hasOne('App\Models\ProductDelete');
}
public function isLikedByAuthUserRelation()
{
return $this->belongsToMany('App\Models\User', 'products_likes', 'product_id', 'user_id')->withTimestamps()->where('user_id', auth()->id())->where('value', 1);
}
public function isDislikedByAuthUserRelation()
{
return $this->belongsToMany('App\Models\User', 'products_likes', 'product_id', 'user_id')->withTimestamps()->where('user_id', auth()->id())->where('value', -1);
}
public function isMarkedAuthUserRelation()
{
return $this->belongsToMany('App\Models\User', 'products_marks', 'product_id', 'user_id')->withTimestamps()->where('user_id', auth()->id());
}
public function isExpiredByAuthUserRelation()
{
return $this->belongsToMany('App\Models\User', 'products_expires', 'product_id', 'user_id')->withTimestamps()->where('user_id', auth()->id());
}
public function isReportedByAuthUserRelation()
{
return $this->belongsToMany('App\Models\User', 'products_reports', 'product_id', 'user_id')->withTimestamps()->where('user_id', auth()->id());
}
/**
* @Attributes
*/
public function getActionsAttribute()
{
return [
'show' => [
'route' => route('product.show', [
strtolower($this->productType->name),
$this->slug
]),
'method' => Route::getRoutes()->getByName('product.show')->methods()[0]
],
'report' => [
'route' => route('product.report', $this->slug),
'method' => Route::getRoutes()->getByName('product.report')->methods()[0]
],
'delete' => [
'route' => route('product.deleteRequest', $this->slug),
'method' => Route::getRoutes()->getByName('product.deleteRequest')->methods()[0]
],
'createComment' => [
'route' => route('comment.create', ['product', $this->id]),
'method' => Route::getRoutes()->getByName('comment.create')->methods()[0]
],
'mark' => [
'route' => route('product.mark', $this->slug),
'method' => Route::getRoutes()->getByName('product.mark')->methods()[0]
],
'unmark' => [
'route' => route('product.unmark', $this->slug),
'method' => Route::getRoutes()->getByName('product.unmark')->methods()[0]
],
'like' => [
'route' => route('product.like', $this->slug),
'method' => Route::getRoutes()->getByName('product.like')->methods()[0]
],
'dislike' => [
'route' => route('product.dislike', $this->slug),
'method' => Route::getRoutes()->getByName('product.dislike')->methods()[0]
],
'expired' => [
'route' => route('product.expired', $this->slug),
'method' => Route::getRoutes()->getByName('product.expired')->methods()[0]
],
'showComments' => [
'route' => route('comments.show', ['product', $this->id]),
'method' => Route::getRoutes()->getByName('comments.show')->methods()[0]
],
'linkGeneral' => [
'route' => route('product.link.click.general', $this->slug),
'method' => Route::getRoutes()->getByName('product.link.click.general')->methods()[0]
],
'linkDetails' => [
'route' => route('product.link.click.details', $this->slug),
'method' => Route::getRoutes()->getByName('product.link.click.details')->methods()[0]
],
'linkSubheader' => [
'route' => route('product.link.click.subheader', $this->slug),
'method' => Route::getRoutes()->getByName('product.link.click.subheader')->methods()[0]
]
];
}
public function getIsLikedByAuthUserAttribute()
{
return $this->isLikedByAuthUser();
}
public function getIsDislikedByAuthUserAttribute()
{
return $this->isDislikedByAuthUser();
}
public function getSumLikesAttribute()
{
return $this->sumLikes();
}
public function getIsMarkedAuthUserAttribute()
{
return $this->isMarkedAuthUser();
}
public function getIsReportedByAuthUserAttribute()
{
return $this->isReportedByAuthUser();
}
public function getIsExpiredByAuthUserAttribute()
{
return $this->isExpiredByAuthUser();
}
public function getIsSubscribedByAuthUserAttribute()
{
//Late TODO implement
return false;
}
public function getImageAttribute()
{
return Cache::rememberForever('product_main_image.small.' . $this->slug, function () {
return $this->getFirstMediaUrl('product_main_image', 'small');
});
}
public function getImageFullAttribute()
{
return Cache::rememberForever('product_main_image.' . $this->slug, function () {
return $this->getFirstMediaUrl('product_main_image');
});
}
public function getStrippedContentAttribute()
{
return preg_replace([
'/<(?:br|p|li)[^>]*>/i', //replace br p li with ' '
'/<[^>]*>/', //replace any tag with ''
'/\s+/u', //remove run on space - replace using the unicode flag
'/^\s+|\s+$/u' //trim - replace using the unicode flag
], [
' ', '', ' ', ''
], html_entity_decode($this->description, ENT_QUOTES, 'UTF-8'));
}
/**
* @Custom_functions
*/
public function deleteProductMainImageFromCache()
{
Cache::delete('product_main_image.small.' . $this->slug);
Cache::delete('product_main_image.' . $this->slug);
}
public function getPageStatus()
{
return $this->pageStatus->status;
}
public function sumLikes()
{
return array_sum($this->likes->pluck('pivot.value')->toArray());
}
public function isLikedByAuthUser()
{
return (bool) $this->isLikedByAuthUserRelation->count();
}
public function isDislikedByAuthUser()
{
return (bool) $this->isDislikedByAuthUserRelation->count();
}
public function isReportedByAuthUser()
{
return (bool) $this->isReportedByAuthUserRelation->count();
}
public function isExpiredByAuthUser()
{
return (bool) $this->isExpiredByAuthUserRelation->count();
}
public function isMarkedAuthUser()
{
return (bool) $this->isMarkedAuthUserRelation->count();
}
public function registerMediaCollections(): void
{
$this
->addMediaCollection('product_main_image')
->useDisk('productFiles')
->singleFile()
->useFallbackUrl(asset('storage/media-assets/placeholders/DealBee-No-IMG-Placeholder.png'))
->registerMediaConversions(function (Media $media) {
$this->addMediaConversion('small')
->width(250)
->height(250);
});
$this
->addMediaCollection('product_description_images')
->useDisk('productFiles')
//->withResponsiveImages()
->registerMediaConversions(function (Media $media) {
$this->addMediaConversion('medium')
->width(400)
->height(400);
});
}
}
Started a new Conversation Composer Package: How To Access Global (Laravel) Routes
Hello,
at the moment I am coding a composer package which is providing me some basic function to write tests for Laravel Nova. However, I want to access some standard routes in my package like route('nova.index')
.
The problem is that I cannot simply call route('nova.index')
because then I get the error Symfony\Component\Routing\Exception\RouteNotFoundException: Route [nova.index] not defined.
. But this is only because my package simply cannot access any routes from my actual Laravel project.
So, this brings me to my questions: How can I access routes in my own coded composer project?
I know how to register additional routes in a composer package, but that is not what I want. I want to access already available routes. Any ideas?
Kind regards
Replied to Laravel Reset Password Notification Does Not Get Dispatched In Test But Does Send An Email
Where do you want me to change the use
? In my test or in the ResetPassword
Class?
Replied to Laravel Reset Password Notification Does Not Get Dispatched In Test But Does Send An Email
Thats not working frr me.. I get Error: Call to undefined method Illuminate\Notifications\Notification::fake()
Replied to Laravel Reset Password Notification Does Not Get Dispatched In Test But Does Send An Email
Also no, when testing it with assertQueued
I also get an error that the Illuminate\Auth\Notifications\ResetPassword]
is not queued
Started a new Conversation Laravel Reset Password Notification Does Not Get Dispatched In Test But Does Send An Email
I am writing tests for my Laravel project. Right now I am testing the authentication code like login, logout, reset password and so on.
Sadly, my test is failing because there is no notification send. I have mocked the notifications but assertSendTo
always fails with the reason The expected [Illuminate\Auth\Notifications\ResetPassword] notification was not sent.
.
However, when actual requesting a reset password email (not in the test, as a normal user on my website) I indeed do get an reset password email. So, it is functional and working but not in my test. How can this be? The .evn
is also correct, I have set my mail host to mailtrap.io
and I also receive this email... This is the best proof I can give you.
Here is my test:
use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
use Tests\TestCase;
class AuthTest extends TestCase
{
/** @test */
public function a_not_logged_in_user_can_request_a_new_password()
{
Notification::fake();
$email = Str::random() . "@gmail.com";
$current_password = Str::random(16);
$current_password_hash = Hash::make($current_password);
$user = User::factory()->create([
'email' => $email,
'password' => $current_password_hash
]);
$response = $this->json('POST', route('password.email'), ['email' => $email]);
$response->assertStatus(200);
$response->assertLocation(route('home'));
//$this->expectsNotification($user, ResetPassword::class);
Notification::assertSentTo($user, ResetPassword::class);
}
}
Any ideas why the test is not working or whats wrong with it?
Whats also very strange is the fact that the response code 200
is indicating that everything succeeded without any problem.
This is the error I get when executing the test with assertSentTo
1) Tests\Feature\Auth\LoggedIn\ForgotPassword\AuthTest::a_not_logged_in_user_can_request_a_new_password
The expected [Illuminate\Auth\Notifications\ResetPassword] notification was not sent.
Failed asserting that false is true.
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:68
/MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261
MyWebsiteProject/tests/Feature/Auth/LoggedIn/ForgotPassword/AuthTest.php:35
And this is the error I get when executing it with expectsNotification
1) Tests\Feature\Auth\LoggedIn\ForgotPassword\AuthTest::a_logged_in_user_can_request_a_new_password
The following expected notification were not dispatched: [Illuminate\Auth\Notifications\ResetPassword]
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php:281
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:237
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:153
Kind regards and thank you!
Thank you both. The solution from @s4muel is working!
But if anyone has a better solution, please feel free to comment!
@s4muel yes, thank you as well! I have not tested it yet. But you are also writing "anyway i think it could be better to separate it". But I will test it ASAP!
Thanks for the answer @jeromefitzpatrick! But you are saying "You should probably consider a different solution.". Do you have any other solution or idea how I can solve this?
Started a new Conversation Laravel Relationship: Accessing Method Of Another Model In A Relationshop Retrievs Always The First Entry (wrong Entry)
Hi,
I have found a very strange behavior. I have a User
model, a Role
model, many other models like a Comments
model or a Page
model because a page
can have comments
and so on. However, I have simplified the problem and even created a new project to reproduce this problem. And I am facing the same problem as I am in my own project. I have also attached the repo so you can test it on your own (download link at the end of this text).
My problem is that a User
has one Role
which is assigned by the role_id
in the User
table. No problem so far. However, in my User
model I have assigned a belongsTo
relationship to the Role
model to get the role of the user.
Why I am doing this? Because only people with certain roles should be able to see certain pages or comments for exmaple. So, I am basically checking if the user has the permission to see certain pages.
The problem I am facing now is that any user I choose, always has the superadmin
role. The superadmin
role is the first role along my two other roles in my Role
table. Besides superadmin
I also have to role admin
and user
. Please check out the repo, I have also created migrations and seeders so you can easily reproduce the problem.
But this problem only occurs when my Page
model performs eager loading
via the protected $with
variable or in the controller when using $page->load('comments')
. When eager loading
is activated, the user, no matter which one, always has the first role which there is superadmin.
For me this is not normal and sounds like a bug? I am also very confused because I only have this problem with my role
relationship and no other relationship. Maybe I cannot use the name role
?
What I am basically trying to do is to check weather the user is admin or not via the ->isAdmin()
function in my User
model. Which also is very strange when I call the ->isAdmin()
method via php artisan tinker
or basically inside my view
the user has the correct role. But why doesn't the user has the correct role when accessing it in a relationship?
Here you can download my repo. After you have downloaded it, please run the migrations and seeders and call the URI /page/1
. There you can see a dump which says superadmin
although User 2
has the role called user
. Then switch the $with
attribute in my Page
model form comments
to test
and you can see the user will have the correct role as the role is resolved in the view
itself.
Note 1: I wanted to keep the repo as small as possible. So, I have not implemented a login and authenticate feature. All queries are made on the User
with the id 2
. This user has the role called user
. However, I have tested if it makes any difference if I am using the auth
user or just any User
from the database. It doesn't make any difference. So, it also has nothing to do with auth
.
Note 2: Even when performing a refresh
on my model the role relationship still is wrong!
Note 3: Why I even want to know if the user is admin or not? Because as I mentioned earlier, my page can have comments. Comments have a page status (publish, pending, draft, etc.) and I only want to show to normal users the published comments and to the admins the published and also pending comments so they can approve them. For this I need to perform a if-else
statement and have to check (inside the relationship) via the isAdmin()
function weather to load only published or also pending comments.
Note 4: The user is always the correct when. Even when doing this with auth()->user()
. However, the role
relation is wrong because it always is the first entry in my database which there is superadmin!
I am using PHP 7.4.11
and Laravel 8.15.0
. I will post my code here as well:
Role migration:
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('label')->unique();
$table->timestamps();
});
User migration:
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('role_id')->index();
$table->string('name', 255)->unique();
$table->string('email')->unique()->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->string('password')->nullable();
$table->timestamps();
$table->foreign('role_id')
->references('id')
->on('roles');
});
Page migration:
Schema::create('pages', function (Blueprint $table) {
$table->increments('id');
$table->unsignedBigInteger('user_id')->index();
$table->char('heading')->index();
$table->char('slug')->index()->unique();
$table->mediumText('content');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('restrict');
});
Role seeder:
\DB::table('roles')->delete();
\DB::table('roles')->insert(array (
0 =>
array (
'id' => 1,
'name' => 'superadmin',
'label' => 'Superadmin',
'created_at' => date(now()),
'updated_at' => date(now()),
),
1 =>
array (
'id' => 2,
'name' => 'admin',
'label' => 'Admin',
'created_at' => date(now()),
'updated_at' => date(now()),
),
2 =>
array (
'id' => 3,
'name' => 'user',
'label' => 'User',
'created_at' => date(now()),
'updated_at' => date(now()),
),
));
User seeder
\DB::table('users')->delete();
\DB::table('users')->insert(array (
0 =>
array (
'id' => 1,
'role_id' => 1,
'name' => 'MyName',
'email' => '[email protected]',
'email_verified_at' => date(now()),
'password' => 'mypassword',
'created_at' => date(now()),
'updated_at' => date(now())
),
1 =>
array (
'id' => 2,
'role_id' => 3,
'name' => 'ThisIsMyName',
'email' => '[email protected]',
'email_verified_at' => date(now()),
'password' => 'mypassword',
'created_at' => date(now()),
'updated_at' => date(now())
)
));
Page seeder:
\DB::table('pages')->delete();
\DB::table('pages')->insert(array (
0 =>
array (
'id' => 1,
'user_id' => 1,
'heading' => 'My Test Heading',
'slug' => 'my-test-heading',
'content' => 'This is my content',
'created_at' => date(now()),
'updated_at' => date(now())
),
1 =>
array (
'id' => 2,
'user_id' => 1,
'heading' => 'My Test Heading 1',
'slug' => 'my-test-heading-1',
'content' => 'This is my content',
'created_at' => date(now()),
'updated_at' => date(now())
))
);
Role model:
class Role extends Model
{
use HasFactory;
/**
* @Protected_variables
*/
protected $table = 'roles';
protected $guarded = ['id'];
/**
* @Public_variables
*/
/**
* @Relationships
*/
/**
* @Attributes
*/
/**
* @Custom_functions
*/
public static function getIdByName($name)
{
return Cache::rememberForever('getRoleIDByName.'.$name, function() use ($name)
{
return self::where('name', $name)->first()->id;
});
}
}
User model:
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $table = 'users';
protected $guarded = ['id'];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function role()
{
return $this->belongsTo('App\Models\Role', 'role_id', 'id');
}
public function hasRole($roleNames)
{
//dd($this->role->id);
$role = $this->refresh()->role->name;
if(is_array($roleNames)){
return in_array($role, $roleNames);
}
if(is_string($roleNames)){
return $role == $roleNames;
}
return false;
}
public function isAdmin($authorized = array('admin', 'superadmin'))
{
return $this->hasRole($authorized);
}
}
Page model
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
protected $table = 'pages';
protected $guarded = ['id'];
protected $with = ['comments'];
protected $casts = [
'publish_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
public function test(){
return $this->belongsTo('App\Models\User');
}
public function comments()
{
$user = User::find(2);
if($user->isAdmin()){
dd("I am FALSELY admin!");
dump($user->role->name . " <- This is wrong!");
dump(json_encode($user->isAdmin()) . " <- This is wrong!");
}else{
return $this->belongsTo('App\Models\User');
}
}
public function user()
{
return $this->belongsTo('App\Models\User');
}
}
Kind regards
Replied to Laravel Nova: Delete Images From Disk When Content Is Modified And Image Is Removed
@bobbybouwmann Do you have any article or documentation where I can look that up?
Started a new Conversation Vue Js Clipboard: How To Allow Quill Mention Chars?
Hi,
I am using this package here to support mentions within my comments. The problem I am facing is that when I type a @
and select a user everything works fine! The mention tag is getting placed correct!
But when I edit an comment again the mention gets kind of destroy. Normally the mention looks like this @myuser
. But when clicking on edit the mention looks like this @a href="http://mywebsiteproject.test/user/myuser" target=_blankmyuser
.
I know this comes from another package I am using which is called quill-paste-smart.
So, there is a problem which the text which gets pasted into the textfield... But I don't know why. The HTML Tag of a mention looks like this:
<span class="mention" data-index="0" data-denotation-char="@" data-id="1" data-value="<a href="http://mywebsiteproject.test/user/myuser" target=_blank>myuser" data-link="http://mywebsiteproject.test/user/myuser">
<span contenteditable="false">
<span class="ql-mention-denotation-char">@</span>
<a href="http://mywebsiteproject.test/user/myuser" target="_blank">myuser</a>
</span>
</span>
But after I pressed edit the html tags look like this:
<span class="mention" data-index="0" data-denotation-char="@" data-id="1" data-value="a href="http://mywebsiteproject.test/user/DealBee" target=_blankDealBee" data-link="http://mywebsiteproject.test/user/DealBee">
<span contenteditable="false">
<span class="ql-mention-denotation-char">@</span>
a href="http://mywebsiteproject.test/user/DealBee" target=_blankDealBee
</span>
</span>
=> Basically there is a problem with the tag..
This is how my clipboard module looks like:
clipboard: {
allowed: {
tags: ['a', 'b', 'strong', 'u', 's', 'i', 'p', 'br', 'ul', 'ol', 'li', 'span'],
attributes: ['href', 'rel', 'target', 'class', 'data-index', 'data-denotation-char', 'data-id', 'data-value', 'data-link', 'contenteditable', 'ql-mention-denotation-char']
},
keepSelection: true,
},
Does anybody know how to fix this problem/allow the mention tags and attributes?
Kind regards
Replied to Laravel Nova: Delete Images From Disk When Content Is Modified And Image Is Removed
@bobbybouwmann is it also possible to do this only for models/queries which come from nova? Because I don't need to modify those which are coming from the normal front end as they are already modified!
Started a new Conversation Laravel Nova: Delete Images From Disk When Content Is Modified And Image Is Removed
Hi,
I am working with spatie media library to store my images. On the frontend site I am using Quill editor with Vue js to give users the option to modify their posts. The users on the frontend also have the option to upload images. Those images get send in base64 within the content.
On the server side I am checking if the content contains any images which are base64 encoded. If so, I store them via spatie media library and replace the base64 image tag with and an img tag which has the image link as source set. This happens BEFORE storing the content to the database.
Same procedure for updating the content. I check if all images which are stored for the post model in the spatie media library are still within the content. If not, delete those images. When there are new images I do the same procedure as described above. If the post gets deleted, the image will also be deleted.
Here you can read the "tutorial" on how to do this.
However, I don't know how I can perform the same procedure when the admin is editing the content... Because I need to modify the query BEFORE the content gets stored as base64 images are way to long for my database.
Does anybody knows how to do this or had an similar problem? I was thinking about observers. But there I have the problem that it is already to late. At the time the observer code is getting executed the content already got stored. This won't work as my database only allows text with around 64.000 chars. I also don't want to change that!
Second problem with observers will be that I will end up in a infinity loop because I need to call ->save()
on my model which will trigger the observer again...
Any ideas on this? Basically I need to catch the SQL query before it will get executed.
Kind regards and thank you!
Started a new Conversation Laravel Nova: Modify Value (muliply) Before Saving To Database
Hi,
I am using Laravel Nova to administrate my project. However, I save certain values in my database like percentages or prices as x*100
. Why I am doing this? Because when saving numbers *100
I can store them as int
instead of double
or float
.
However, this leads to the problem that I am seeing the number which is saved and multiplied by 100 in the database on my Laravel Nova Admin dashboard. I mean I can bypass that by using resolveUsing
or displayUsing
(read here). Then e.g. 1530
will be presented as 15,30
when diving by 100
which is correct.
The only problem with this is when typing 100 in the percentage field e.g. it also gets saved as 100 and not as 10000 (100*100). Does anybody knows how I can implement this?
I also tried to use eloquent observers. But this doesn't work because I end up in a infinity loop.
Kind regards and thank you!
Replied to Computed Column In Value / Trend Metrics
@bobbybouwmann I get Property total does not exist on the Eloquent builder instance
. Do you know why that? I am using Laravel 8 and Nova 3.
I do exactly the same thing except my Model is called Product
. I want to sum up the link_clicks_general
and link_clicks_details
.
public function calculate(NovaRequest $request)
{
$product = Product::selectRaw('SUM(link_clicks_general + link_clicks_details) as total');
return (new \Laravel\Nova\Metrics\ValueResult($product->total))
->format(['thousandSeparated' => true])
->currency('$');
}
Started a new Conversation Laravel Eloquent Belongs To Many Query Returns Entries Multiple Time
I have a products
, users
and products_marks
table. Users can "mark" products. When they mark one product the database stores the user_id
and the product_id
in the products_marks
table.
Marks basically mean a user wants to watch this product and has a watchlist. Of course I want to show the user all products he has marked. This means I have to get all products where the user_id
in the products_marks
table matches the actually user. However, I have some extra requirements to this as well.
Products do have a post_status_id
. This represents weather the product is publish, offline, in review, pending, etc. The marked products should only be represented to the user if the product is also online. BUT if the user has marked a product which he has posted by himself, so he is the owner of the product, he should also see this product when it is publish AND pending.
This also works in most cases. I already have an eloquent query for this. But now I have found a strange problem. A user reported me that he sees one product two times in his watchlist. I have run the SQL query for exactly this user and yes, the database is returning the product two times! Why this? What do I have to change in order to get each product only once?
User model:
/** Relationship */
public function markedProducts(){
return $this->belongsToMany('App\Models\Product', 'products_marks');
}
/** Eloquent Query */
public static function markedProductsPaginated(User $user){
$products = Product::select('products.*')
->join('products_marks', 'products_marks.product_id', '=', 'products.id')
->whereHas('marks', function ($query) use ($user) {
$query->where(function($query) use ($user){
$query->where('products_marks.user_id', $user->id);
});
$query->where(function($query){
$query->where('page_status_id', PageStatus::getIdByStatus('publish'));
});
$query->orWhere(function($query) use ($user){
$query->where('page_status_id', PageStatus::getIdByStatus('pending'))
->where('products.user_id', $user->id);
});
})
->orderBy('products_marks.created_at', 'desc')
->paginate(10);
$products->loadCount('allPublishedComments');
return $products;
}
Query as SQL statement:
select `products`.* from `products` inner join `products_marks` on `products_marks`.`product_id` = `products`.`id` where exists (select * from `users` inner join `products_marks` on `users`.`id` = `products_marks`.`user_id` where `products`.`id` = `products_marks`.`product_id` and ((`products_marks`.`user_id` = 19) and (`page_status_id` = 1) or (`page_status_id` = 4 and `products`.`user_id` = 3))) order by `products_marks`.`created_at` desc limit 10 offset 0
I have also created a db fiddle here where you can run this SQL statement and see that the database is returning the entry for the user_id 13
two times. But why is that? And why only sometimes?
It looks like when multiple users mark the same product I get it multiple times back. As you can see in the fiddle the product with the id 43
got marked two times!
Kind regards and thank you!
Awarded Best Reply on Laravel FormRequest Validation Gets User Model And Sometimes Directly The Name
If anybody else is facing this problem, I found the solution. Well, at least I found the problem I have:
I did forget to pass the User $user
to my validate function... Check your function parameters!
Replied to Laravel FormRequest Validation Gets User Model And Sometimes Directly The Name
If anybody else is facing this problem, I found the solution. Well, at least I found the problem I have:
I did forget to pass the User $user
to my validate function... Check your function parameters!
Replied to Laravel FormRequest Validation Gets User Model And Sometimes Directly The Name
Thanks for your answer!
However, I have exactly the same problem as written above just not with $this->user
or $this->user->name
but with $this->route('user')
or $this->route('user')->name
...
Why does it either return the user object
or cannot access the property name
?
Started a new Conversation Laravel FormRequest Validation Gets User Model And Sometimes Directly The Name
Hi,
I am using Laravel 8 and validate my requests with the form request validation. However, I have a strange problem. Before I am going to describe my problem I will paste my routes and my validation class here:
routes:
Route::post('users', ['as' => 'user.search', 'uses' => '[email protected]']);
Route::post('user/name', ['as' => 'user.name.exists', 'uses' => '[email protected]']);
Route::post('user/email', ['as' => 'user.email.exists', 'uses' => '[email protected]']);
Route::post('user/email/check', ['as' => 'user.email.check', 'uses' => '[email protected]']);
Route::get('user/{user:name}', ['as' => 'user.show', 'uses' => '[email protected]']);
Route::get('user/{user:name}/einstellungen', ['as' => 'user.settings', 'uses' => '[email protected]']);
Route::get('user/{user:name}/produkte', ['as' => 'user.products', 'uses' => '[email protected]']);
Route::post('user/{user:name}/produkte', ['as' => 'user.products.post', 'uses' => '[email protected]']);
Route::get('user/{user:name}/saved/produkte', ['as' => 'user.marked.products', 'uses' => '[email protected]']);
Route::post('user/{user:name}/saved/produkte', ['as' => 'user.marked.products.post', 'uses' => '[email protected]']);
Route::post('user/{user:name}/avatar/upload', ['as' => 'user.avatar.update', 'uses' => '[email protected]']);
Route::post('user/{user:name}/avatar/valid', ['as' => 'user.avatar.valid', 'uses' => '[email protected]']);
Route::post('user/{user:name}/avatar/löschen', ['as' => 'user.avatar.delete', 'uses' => '[email protected]']);
Route::post('user/{user:name}/update/password', ['as' => 'user.password.change', 'uses' => '[email protected]']);
Route::post('user/{user:name}/validate/password', ['as' => 'user.password.validate', 'uses' => '[email protected]']);
This is my FormRequest
validation which checks if the user is authorized to perform this request and if the given data are valid. As you can see, I check if the Auth::user()->name
is the same as the requested user ($this->user->name
) to change the image. Because only the owner of his profile image should be allowed to change is profile image.
class UserAvatarUpdateRequest extends FormRequest
{
public function authorize()
{
dump(array('auth' => Auth::user()->name, 'requested' => $this->user));
if(Auth::check() && Auth::user()->name == $this->user->name){
return true;
}
return false;
}
public function rules()
{
return [
'avatar' => [
'required',
'image',
'max:5000',
'mimes:jpeg,png,jpg',
Rule::dimensions()->minWidth(200)->minHeight(200)->ratio(1)
],
];
}
}
Now I will come to the problem. As you can see I have several routes for my user and there is one route called user.avatar.valid
and another route called user.avatar.update
.
Both routes, user.avatar.valid
and user.avatar.update
are using the FormRequest
validation class I have pasted above. Basically user.avatar.valid
is being called before the user submits the form to check if the uploaded image is valid. I know, I also could do this in one request but that's not possible because I am using vee-validate
for Vuejs to validate if the form is valid.
However, thats not the probleme here. The problem is that when calling the user.avatar.valid
route my dump echos for the key requested
the name
of the requested user. But, when performing a request for user.avatar.update
I don't get the name
of the user but rather the user object
which contains the id
, name
, email
and so on.
But exactly this is the point... when trying to call user.avatar.update
I get a 403
error (forbidden) because $this->user
is not equal to Auth::user()->name
. Obviously it is not the same when I compare a string
(name) to the user object
.
However, when calling user.avatar.valid
it passes because here I get the name
when calling $this->user
and not the user object
.
But why is that?
When I change $this->user
to $this->user->name
I get the actual name for the user when calling the user.avatar.update
route but on the other side I get a 500
error when calling the user.avatar.valid
route because it says Trying to get property 'name' of non-object
...
Does anybody has an idea where the problem here is and how to fix this?
Kind regards and thank you!
Replied to Laravle 8 Wrong Timezone (-1) When ->toArray() A Collection
My fault... it's just being casted to a utc format... All good!
Started a new Conversation Laravle 8 Wrong Timezone (-1) When ->toArray() A Collection
Hi,
I have set my timezone
in config/app.php
to Europe/Berlin
. I know Laravel has changed the date format from Laravel 6 to Laravel 7 to the ISO 8601 format. But that's not the problem here..
My problem is that I get different times when using the toArray()
function on a collection.
Here is an example:
$product = Product::where('id', '1')->get();
dd($product->end_date)
The dd()
returns
Illuminate\Support\Carbon @1607547599 {#1949 ▼
#constructedObjectId: "0000000076d58c550000000061b504d8"
#localMonthsOverflow: null
#localYearsOverflow: null
#localStrictModeEnabled: null
#localHumanDiffOptions: null
#localToStringFormat: null
#localSerializer: null
#localMacros: null
#localGenericMacros: null
#localFormatFunction: null
#localTranslator: null
#dumpProperties: array:3 [▶]
#dumpLocale: null
date: 2020-12-09 21:59:59.0 Europe/Berlin (+01:00)
}
Even when using doing a toArray()
on the Carbon
class (dd($product->end_date->toArray())
) I get the correct time:
array:12 [▼
"year" => 2020
"month" => 12
"day" => 9
"dayOfWeek" => 3
"dayOfYear" => 344
"hour" => 21
"minute" => 59
"second" => 59
"micro" => 0
"timestamp" => 1607547599
"formatted" => "2020-12-09 21:59:59"
"timezone" => Carbon\CarbonTimeZone {#1986 ▶}
]
However, and here comes the problem now, when performing a toArray()
on the collection I don't get 2020-12-09 21:59:59
but rather 2020-12-09T20:59:59.000000Z
which is 1 hour to less.
dd($product->toArray()['end_date']);
Results in 2020-12-09T20:59:59.000000Z
.
But why? Where is the problem? Why is one hour missing? Did I missed something in the upgrade guide?
Kind regards
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
Thanks! You are a legend!
May any idea on my other thread about the comments and child comments?
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
But this leads to the problem that my $appends
attributes are not correct anymore...
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
Yes, this is working. But I want to sort the complete relation either by products_marks.id
or products_marks.created_at
... how can I do this?
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
I think I have it know. Is this correct?
$products = Product::whereHas('marks', function ($query) use ($user) {
$query->where('products_marks.user_id', $user->id)
->where('page_status_id', PageStatus::getIdByStatus('publish'))
->orWhere('page_status_id', PageStatus::getIdByStatus('pending'))
->where('products.user_id', $user->id);
})
->orderBy('created_at', 'desc')
->paginate(10);
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
Yes, you are right!
This is my query at the moment:
$products = Product::whereHas('marks', function ($query) use ($user) {
$query->where('products_marks.user_id', $user->id);
})
->where('page_status_id', PageStatus::getIdByStatus('publish'))
->orWhere('page_status_id', PageStatus::getIdByStatus('pending'))
->orderBy('created_at', 'desc')
->paginate(10);
page_status_id
represents whether a product is published (1) or pending (4). I want to get only published articles OR pending articles where the logged in user is also the author (products.user_id) of the product.
Replied to Laravel Eloquent: Only Retriev Entries Where Relationship Has Entries (join)
Yes, this is working. Thank you. However, I do get all products instead of only the marked
once.. is my relation wrong?
This is what I get as raw SQL:
select * from products where exists (select * from users inner join products_marks on users.id = products_marks.user_id where products.id = products_marks.product_id and products_marks.user_id = 2) and page_status_id = 1 or page_status_id = 4 order by created_at desc
Replied to Laravel Eloquent: Sort Table By Sum Count Of Two Tables
Yes, I know... but this is how it is implemented now and it would be a huge effort to change this. Maybe I will do this later... but I need a solution for the current problem.