FrazeColder

Member Since 2 Years Ago

Experience Points
2,470
Total
Experience

2,530 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
3
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    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.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

  • Community Pillar

    Earned once your experience points ranks in the top 10 of all Laracasts users.

Level 1
2,470 XP
Mar
20
4 weeks ago
Activity icon

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...

Activity icon

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.

  1. 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?

  2. 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

Mar
16
1 month ago
Activity icon

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.

Activity icon

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

Activity icon

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}
"} 
Activity icon

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))
Activity icon

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!

Mar
15
1 month ago
Activity icon

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

Activity icon

Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis

Thanks for your reply, but sadly also not working...

Activity icon

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...

Activity icon

Replied to Laravel 8: QueueManager.php:156 Array Offset Of Type Null / Configure Redis

@andy abi haidar

Yes, now I get null!

Why is this?

Activity icon

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),
        ],

    ],

];

Activity icon

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

Activity icon

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

Mar
05
1 month ago
Activity icon

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.)

Activity icon

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

Activity icon

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.

Activity icon

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!

Mar
02
1 month ago
Activity icon

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);
            });
    }
}
Feb
26
1 month ago
Activity icon

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

Feb
21
1 month ago
Activity icon

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?

Activity icon

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()

Feb
20
1 month ago
Activity icon

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

Activity icon

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!

Feb
09
2 months ago
Activity icon

Replied to Laravel Relationship: Accessing Method Of Another Model In A Relationshop Retrievs Always The First Entry (wrong Entry)

Thank you both. The solution from @s4muel is working!

But if anyone has a better solution, please feel free to comment!

Activity icon

Replied to Laravel Relationship: Accessing Method Of Another Model In A Relationshop Retrievs Always The First Entry (wrong Entry)

@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!

Activity icon

Replied to Laravel Relationship: Accessing Method Of Another Model In A Relationshop Retrievs Always The First Entry (wrong Entry)

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?

Feb
08
2 months ago
Activity icon

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

Feb
07
2 months ago
Activity icon

Started a new Conversation Closed

[Please close this topic]

Nov
23
4 months ago
Activity icon

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?

Nov
22
4 months ago
Activity icon

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=&quot;http://mywebsiteproject.test/user/myuser&quot; 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=&quot;http://mywebsiteproject.test/user/DealBee&quot; 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

Nov
21
4 months ago
Activity icon

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!

Activity icon

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!

Nov
20
4 months ago
Activity icon

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!

Activity icon

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('$');
    }
Nov
19
4 months ago
Activity icon

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!

Activity icon

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!

Activity icon

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!

Nov
13
5 months ago
Activity icon

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?

Activity icon

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!

Nov
10
5 months ago
Activity icon

Replied to Laravle 8 Wrong Timezone (-1) When ->toArray() A Collection

My fault... it's just being casted to a utc format... All good!

Activity icon

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

Activity icon

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?

Activity icon

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...

Activity icon

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?

Activity icon

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);
Activity icon

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.

Activity icon

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

Activity icon

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.