Skip to content

Commit 79056ac

Browse files
Docker image updates (limosa-io#125)
1 parent f48efe7 commit 79056ac

File tree

2 files changed

+129
-20
lines changed

2 files changed

+129
-20
lines changed

Dockerfile

Lines changed: 119 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
FROM php:8.1-alpine
22

3-
RUN apk add --no-cache git jq moreutils
4-
RUN apk add --no-cache $PHPIZE_DEPS postgresql-dev \
5-
&& docker-php-ext-install pdo_pgsql \
3+
# Base tools and PHP extensions
4+
RUN apk add --no-cache git jq moreutils \
5+
&& apk add --no-cache $PHPIZE_DEPS postgresql-dev sqlite-dev \
6+
&& docker-php-ext-install pdo_pgsql pdo_sqlite \
67
&& pecl install xdebug-3.1.5 \
78
&& docker-php-ext-enable xdebug \
89
&& echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
910
&& echo "xdebug.client_host = 172.19.0.1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
1011

12+
# Composer + fresh Laravel app
1113
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
12-
RUN composer create-project --prefer-dist laravel/laravel example && \
13-
cd example
14+
RUN composer create-project --prefer-dist laravel/laravel example && cd example
1415

1516
WORKDIR /example
1617

18+
# Link local package
1719
COPY . /laravel-scim-server
1820
RUN jq '.repositories=[{"type": "path","url": "/laravel-scim-server"}]' ./composer.json | sponge ./composer.json
1921

22+
# Install package and dev helpers
2023
RUN composer require arietimmerman/laravel-scim-server @dev && \
2124
composer require laravel/tinker
2225

26+
# SQLite config
2327
RUN touch /example/database.sqlite && \
2428
echo "DB_CONNECTION=sqlite" >> /example/.env && \
2529
echo "DB_DATABASE=/example/database.sqlite" >> /example/.env && \
2630
echo "APP_URL=http://localhost:18123" >> /example/.env
2731

32+
# Make users.password nullable to allow SCIM-created users without passwords
33+
RUN sed -i -E "s/\\$table->string\('password'\);/\\$table->string('password')->nullable();/g" \
34+
database/migrations/*create_users_table.php || true
2835

29-
# Add migration for groups table using heredoc
36+
# Groups table migration
3037
RUN cat > /example/database/migrations/2021_01_01_000001_create_groups_table.php <<'EOM'
3138
<?php
3239

@@ -51,44 +58,49 @@ return new class extends Migration {
5158
};
5259
EOM
5360

54-
# Add Group model
61+
# Group model with members() relation
5562
RUN cat > app/Models/Group.php <<'EOM'
5663
<?php
5764

5865
namespace App\Models;
5966

6067
use Illuminate\Database\Eloquent\Model;
6168
use Illuminate\Database\Eloquent\Factories\HasFactory;
69+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
70+
use App\Models\User;
6271

6372
class Group extends Model
6473
{
6574
use HasFactory;
6675

6776
protected $fillable = ['displayName'];
77+
78+
public function members(): BelongsToMany
79+
{
80+
return $this->belongsToMany(User::class, 'group_user', 'group_id', 'user_id')->withTimestamps();
81+
}
6882
}
6983
EOM
7084

71-
# Add Custom SCIM Config overriding Group model class
85+
# Override SCIM config to use app's Group model
7286
RUN mkdir -p app/SCIM && cat > app/SCIM/CustomSCIMConfig.php <<'EOM'
7387
<?php
7488

7589
namespace App\SCIM;
7690

7791
use ArieTimmerman\Laravel\SCIMServer\SCIMConfig as BaseSCIMConfig;
92+
use App\Models\Group;
7893

7994
class CustomSCIMConfig extends BaseSCIMConfig
8095
{
81-
public function getGroupConfig()
96+
public function getGroupClass()
8297
{
83-
$config = parent::getGroupConfig();
84-
// Force the group model to the example app's Group model
85-
$config['class'] = \App\Models\Group::class;
86-
return $config;
98+
return Group::class;
8799
}
88100
}
89101
EOM
90102

91-
# Override AppServiceProvider to register custom SCIMConfig binding
103+
# Bind CustomSCIMConfig in the container
92104
RUN cat > app/Providers/AppServiceProvider.php <<'EOM'
93105
<?php
94106

@@ -107,12 +119,12 @@ class AppServiceProvider extends ServiceProvider
107119

108120
public function boot(): void
109121
{
110-
// Additional boot logic if needed
122+
//
111123
}
112124
}
113125
EOM
114126

115-
# Add Group factory
127+
# Group factory
116128
RUN cat > database/factories/GroupFactory.php <<'EOM'
117129
<?php
118130

@@ -134,8 +146,97 @@ class GroupFactory extends Factory
134146
}
135147
EOM
136148

149+
# Pivot table for memberships
150+
RUN cat > /example/database/migrations/2021_01_01_000002_create_group_user_table.php <<'EOM'
151+
<?php
152+
153+
use Illuminate\Database\Migrations\Migration;
154+
use Illuminate\Database\Schema\Blueprint;
155+
use Illuminate\Support\Facades\Schema;
156+
157+
return new class extends Migration {
158+
public function up(): void
159+
{
160+
Schema::create('group_user', function (Blueprint $table) {
161+
$table->id();
162+
$table->foreignId('group_id')->constrained('groups')->cascadeOnDelete();
163+
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
164+
$table->timestamps();
165+
$table->unique(['group_id', 'user_id']);
166+
});
167+
}
168+
169+
public function down(): void
170+
{
171+
Schema::dropIfExists('group_user');
172+
}
173+
};
174+
EOM
175+
176+
# Ensure User model has groups() relation (overwrite default)
177+
RUN cat > app/Models/User.php <<'EOM'
178+
<?php
179+
180+
namespace App\Models;
181+
182+
use Illuminate\Database\Eloquent\Factories\HasFactory;
183+
use Illuminate\Foundation\Auth\User as Authenticatable;
184+
use Illuminate\Notifications\Notifiable;
185+
use Laravel\Sanctum\HasApiTokens;
186+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
187+
188+
class User extends Authenticatable
189+
{
190+
use HasApiTokens, HasFactory, Notifiable;
191+
192+
protected $fillable = [
193+
'name',
194+
'email',
195+
'password',
196+
];
197+
198+
protected $hidden = [
199+
'password',
200+
'remember_token',
201+
];
202+
203+
protected $casts = [
204+
'email_verified_at' => 'datetime',
205+
];
206+
207+
public function groups(): BelongsToMany
208+
{
209+
return $this->belongsToMany(Group::class, 'group_user', 'user_id', 'group_id')->withTimestamps();
210+
}
211+
}
212+
EOM
213+
214+
# Seeder for demo data
215+
RUN cat > /example/database/seeders/DemoSeeder.php <<'EOM'
216+
<?php
217+
218+
namespace Database\Seeders;
219+
220+
use Illuminate\Database\Seeder;
221+
use App\Models\User;
222+
use App\Models\Group;
223+
224+
class DemoSeeder extends Seeder
225+
{
226+
public function run(): void
227+
{
228+
$users = User::factory()->count(50)->create();
229+
$groups = Group::factory()->count(10)->create();
230+
231+
foreach ($groups as $g) {
232+
$g->members()->sync($users->random(rand(3, 10))->pluck('id')->toArray());
233+
}
234+
}
235+
}
236+
EOM
237+
137238
# Run migrations and seed demo data
138-
RUN php artisan migrate && \
139-
echo "User::factory()->count(100)->create(); App\\Models\\Group::factory()->count(10)->create();" | php artisan tinker
239+
RUN php artisan migrate && php artisan db:seed --class=Database\\Seeders\\DemoSeeder
140240

141241
CMD ["php","artisan","serve","--host=0.0.0.0","--port=8000"]
242+

src/SCIMConfig.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ protected function doRead(&$object, $attributes = [])
7676
{
7777
return (string)$object->id;
7878
}
79+
public function remove($value, &$object, $path = null)
80+
{
81+
// do nothing
82+
}
7983
}
8084
),
8185
new Meta('Users'),
@@ -143,7 +147,7 @@ public function getGroupConfig()
143147
{
144148
return [
145149

146-
'class' => Group::class,
150+
'class' => $this->getGroupClass(),
147151
'singular' => 'Group',
148152

149153
//eager loading
@@ -165,13 +169,17 @@ protected function doRead(&$object, $attributes = [])
165169
{
166170
return (string)$object->id;
167171
}
172+
public function remove($value, &$object, $path = null)
173+
{
174+
// do nothing
175+
}
168176
}
169177
),
170178
new Meta('Groups'),
171179
(new AttributeSchema(Schema::SCHEMA_GROUP, true))->withSubAttributes(
172180
eloquent('displayName')->ensure('required', 'min:3', function ($attribute, $value, $fail) {
173181
// check if group does not exist or if it exists, it is the same group
174-
$group = Group::where('displayName', $value)->first();
182+
$group = $this->getGroupClass()::where('displayName', $value)->first();
175183
if ($group && (request()->route('resourceObject') == null || $group->id != request()->route('resourceObject')->id)) {
176184
$fail('The name has already been taken.');
177185
}

0 commit comments

Comments
 (0)