11FROM 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
1113RUN 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
1516WORKDIR /example
1617
18+ # Link local package
1719COPY . /laravel-scim-server
1820RUN jq '.repositories=[{"type": "path","url": "/laravel-scim-server"}]' ./composer.json | sponge ./composer.json
1921
22+ # Install package and dev helpers
2023RUN composer require arietimmerman/laravel-scim-server @dev && \
2124 composer require laravel/tinker
2225
26+ # SQLite config
2327RUN 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
3037RUN 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};
5259EOM
5360
54- # Add Group model
61+ # Group model with members() relation
5562RUN cat > app/Models/Group.php <<'EOM'
5663<?php
5764
5865namespace App\M odels;
5966
6067use Illuminate\D atabase\E loquent\M odel;
6168use Illuminate\D atabase\E loquent\F actories\H asFactory;
69+ use Illuminate\D atabase\E loquent\R elations\B elongsToMany;
70+ use App\M odels\U ser;
6271
6372class 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}
6983EOM
7084
71- # Add Custom SCIM Config overriding Group model class
85+ # Override SCIM config to use app's Group model
7286RUN mkdir -p app/SCIM && cat > app/SCIM/CustomSCIMConfig.php <<'EOM'
7387<?php
7488
7589namespace App\S CIM;
7690
7791use ArieTimmerman\L aravel\S CIMServer\S CIMConfig as BaseSCIMConfig;
92+ use App\M odels\G roup;
7893
7994class 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'] = \A pp\M odels\G roup::class;
86- return $config;
98+ return Group::class;
8799 }
88100}
89101EOM
90102
91- # Override AppServiceProvider to register custom SCIMConfig binding
103+ # Bind CustomSCIMConfig in the container
92104RUN 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}
113125EOM
114126
115- # Add Group factory
127+ # Group factory
116128RUN cat > database/factories/GroupFactory.php <<'EOM'
117129<?php
118130
@@ -134,8 +146,97 @@ class GroupFactory extends Factory
134146}
135147EOM
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\D atabase\M igrations\M igration;
154+ use Illuminate\D atabase\S chema\B lueprint;
155+ use Illuminate\S upport\F acades\S chema;
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\M odels;
181+
182+ use Illuminate\D atabase\E loquent\F actories\H asFactory;
183+ use Illuminate\F oundation\A uth\U ser as Authenticatable;
184+ use Illuminate\N otifications\N otifiable;
185+ use Laravel\S anctum\H asApiTokens;
186+ use Illuminate\D atabase\E loquent\R elations\B elongsToMany;
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\S eeders;
219+
220+ use Illuminate\D atabase\S eeder;
221+ use App\M odels\U ser;
222+ use App\M odels\G roup;
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
141241CMD ["php" ,"artisan" ,"serve" ,"--host=0.0.0.0" ,"--port=8000" ]
242+
0 commit comments