Open your settings in PHPStorm and go to Tools > File Watchers
Add a new Custom File Watcher and use the following information:
Name: pint
File type: PHP
Program: $ProjectFileDir$/vendor/bin/pint
Arguments: $FileRelativePath$
Output paths to refresh: $FileRelativePath$
Working directory: $ProjectFileDir$
In this post I will show you how to change an existing field in your Laravel application to change to enum.
I have a field status which was kept in line by having class constants defining the value for this field. But I really missed the database keeping the value in line though.
Changing the class constants to a PHP 8 enum and changing the database field to enum had some caveats so if you want to change your datatype to enum as well, follow along.
I use the trait EnumEnhancements
for the enum as this provides very handy helper methods:
ImportStatus::valueArray()
: an array with the values of the enumImportStatus::valueList()
: a string with the values of the enum: ‘pending, validating, importing, …’
<?php
declare(strict_types=1);
namespace App\Models\Enums;
use Othyn\PhpEnumEnhancements\Traits\EnumEnhancements;
enum ImportStatus: string
{
use EnumEnhancements;
case PENDING = 'pending';
case VALIDATING = 'validating';
case VALIDATION_FAILED = 'validation_failed';
case VALIDATED = 'validated';
case CREATING_IMPORT_JOBS = 'creating_import_jobs';
case IMPORT_JOBS_CREATED = 'import_jobs_created';
case IMPORTING = 'importing';
case IMPORTED = 'imported';
case FAILED = 'failed';
case CANCELLED = 'cancelled';
case FINISHED = 'finished';
}
NOTE: changing an existing field to an enum in your database requires you to do this with a DB statement. You cannot use a query builder for this or you’ll get the following error :
Unknown column type "enum" requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database introspection then you might have forgotten to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.
I change the existing column from a string to an enum in 4 steps:
<?php
declare(strict_types=1);
use App\Models\Enums\ImportStatus;
use App\Models\ImportFile;
use Illuminate\Database\Migrations\Migration;
return new class () extends Migration {
public function up(): void
{
// 1. Get the current status for each row
$importFiles = DB::table('posts')->get(['id', 'status']);
// 2. Set all statuses to NULL
DB::table('posts')->update(['status' => null]);
// 3. Change the column to an enum
$this->changeStatusToEnum();
// 4. Set the status for each row to the value we got in step 1
foreach ($products as $product) {
$validStatuses = collect(ImportStatus::valueArray());
$currentStatus = strtolower($product->status ?? '');
$currentStatus = $currentStatus === 'success'
? ImportStatus::FINISHED->value
: $currentStatus;
$newStatus = $validStatuses->contains($currentStatus)
? $currentStatus
: ImportStatus::PENDING->value;
// update the status, if one fails set the status to
// the default value
Post::where('id', $post->id)
->update(['status' => $newStatus]);
}
}
private function changeStatusToEnum(): void
{
// note: enums cannot be changed with migrations.
// It has to be done with a DB statement
$validEnumValues = ImportStatus::valueList("', '");
$defaultValue = ImportStatus::PENDING->value;
$query = "ALTER TABLE posts";
$query .= "MODIFY COLUMN status enum('{$validEnumValues}') ";
$query .= "DEFAULT '{$defaultValue}'";
DB::statement($query);
}
};
A little drawback is that I can no longer refer to the values as ImportStatus::validating
as that is now returning an enum
instead of a string.
To get the value of an enum
you have to call the value
property on it: ImportStatus::validating->value
So change your codebase by replacing ImportStatus::validating
to ImportStatus::validating->value
If you created a foreign key in your database which should have been nullable, you have to create a database migration to fix that.
To make your foreign key nullable, you first need to delete the Foreign Key constraint, then change the field to be nullable and then create the Foreign Key constraint again.
<?php
return new class extends Migration {
public function up(): void
{
Schema::table('retailers', function (Blueprint $table) {
$table->dropForeign('retailers_import_id_foreign');
$table->unsignedBigInteger('import_id')
->nullable(true)
->change();
$table->foreign('import_id')
->references('id')
->on('import_files')
->nullOnDelete()
->cascadeOnUpdate();
});
}
};
Setting up the related testdata when creating Pest tests always keeps me searching for the syntax.
Therefore, here a little reminder to self with links to the appropriate info in the Laravel documentation.
HasMany relations: User hasMany Post
// hasMany relation: User has many Posts - post.user_id is set
$user = User::factory()
->has(Post::factory()->count(3))
->create();
BelongsTo relations (inverse of the hasMany): Post belongsTo User => for()
// belongsTo: post.user_id is set
$post = Post::factory()
->for(User::factory())
->create();
Many to Many: User belongsToMany Role => has()
and hasAttached()
// belongsToMany: using the pivot table. NOTE the array as first argument!
$user = User::factory()
->hasAttached([$tag], [<pivot fields>], 'roles')
->create();
In order to get info about your clients browser, you need to install browscap.
NOTE: you get this same error for different reasons! Check your logfiles to figure out what is the real reason for this error.
Reasons I encountered:
To install Browscap on my Ubuntu (Docker image), I used the following site browscap.org.
It comes down to:
In the terminal (or in your Dockerfile):
# install browscap to get browser information of the client
curl https://browscap.org/stream?q=PHP_BrowsCapINI --output ${PHPDIR}/mods-available/php_browscap.ini
# add it to php.ini under the [browscap] directive
sed -i "s|;browscap = extra/browscap.ini.*|browscap = \"${PHPDIR}/mods-available/php_browscap.ini\"|g" ${PHPDIR}/fpm/php.ini
You can check whether PHP found the browscap file by
phpinfo()
on a page and search for browscap
. It should be mentioned thereget_browser()
with the wrong argumentsThis is a funky one as the ini directive is set.
A look at the laravel log helped: get_browser(): HTTP_USER_AGENT variable is not set, cannot determine user agent name
I used get_browser(null, true)
as I found in an online example, but it really needs the user agent as the first argument.
I fixed it by using: `
get_browser($request->userAgent(), true)
Note that I use Laravel, hence the $request->userAgent()
. You can replace this with $_SERVER['HTTP_USER_AGENT']
just as well.
If this didn’t work out, you might info about your usecase somewhere on these pages:
You might want to order your users by ‘days until their birthday’.
People having their birthday come first, people with no birthday registered (NULL values), come last.
// in User model
public static function getByBirthday()
{
return User::query()
->select('user.*')
->selectRaw(
'365.25 -
(
case
WHEN TIMESTAMPDIFF(day, birthday, CURDATE()) = 0 THEN 364.25
WHEN birthday IS NULL THEN 0
ELSE TIMESTAMPDIFF(day, birthday, CURDATE())
end
mod 365.25
) AS days_till_birthday'
)
->orderBy('days_till_birthday');
}
// use it in your code like
$usersByBirthday = User::getByBirthday()->get();
Execute the following queries to have your ‘created_at’ column the current timestamp upon creation and your ‘updated_at’ the current timestamp upon modification.
// set the default values
DB::statement("ALTER TABLE $table CHANGE created_at created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP")
DB::statement("ALTER TABLE $table CHANGE updated_at updated_at TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP");
This error broke my head the other day.
Whenever I posted a specific form, I got a 502 error.
I only got it to work when I disabled (as in: rebuild Docker image to not contain) xdebug.
When I posted the form, there was this warning: PHP Warning: Unknown: Input variables exceeded 1000
.
A quick search learned that I could set the PHP option max_input_vars
to 3000. This made the whole thing working again so I could focus on why this big form has more than 1000 input vars….
; file xdebug.ini
;comment all to disable xdebug
;zend_extension="xdebug.so"
;xdebug.mode=debug,coverage
;xdebug.client_host=host.docker.internal
;xdebug.client_port=9003
;xdebug.start_with_request=trigger
; set PHP directive to allow for maximum 3000 input vars
; PHP Input Vars is a PHP security measure designed to limit the number
; of post variables you can use to execute a function. It defines the
; number of variables your server can use when running a function.
max_input_vars = 3000
For me, it turned out the stateful
property in config/sanctum.php
was not filled correctly.
After setting it to the default as shown below, it started working.
// file config/sanctum.php
...
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
...
Did this not fix your problem?
Check this post which might help: https://stackoverflow.com/a/69858100
I tried to install Gearman on my Ubuntu 18.04 Docker container and encountered a lot of issues.
This write-up is to save you some valuable time of your life.
TL;DR
apt update
apt install -y g++ uuid-dev gperf libboost-all-dev libevent-dev curl
cd /tmp
curl -LO https://github.com/gearman/gearmand/releases/download/1.1.18/gearmand-1.1.18.tar.gz
tar xvzf gearmand-1.1.18.tar.gz
cd gearmand-1.1.18
./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
make
make test
make install
# Start gearman in the background
gearmand --log-file /var/log/gearmand.log --daemon
To get there, I encountered the following issues:
./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
...
checking test for a working libevent... no
configure: error: Unable to find libevent
Fix: apt install -y libevent-dev
./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu
...
checking whether the Boost::Program_Options library is available... yes
configure: error: Could not find a version of the library!
Fix: apt install -y libboost-all-dev
Installing the PHP client libraries for Gearman
If you intend to use PHP to talk to your Gearman service, use the following to get the libraries installed.
Note: you might not need the last line. This is to enable the Gearman PHP extension in Docker.
cd /tmp \
&& wget https://github.com/wcgallego/pecl-gearman/archive/gearman-2.0.6.tar.gz\
&& tar xvzf gearman-2.0.6.tar.gz \
&& mv pecl-gearman-gearman-2.0.6 pecl-gearman \
&& cd pecl-gearman \
&& phpize \
&& ./configure \
&& make -j$(nproc) \
&& make install \
&& cd / \
&& rm /tmp/gearman-2.0.6.tar.gz \
&& rm -r /tmp/pecl-gearman \
&& docker-php-ext-enable gearman