Overview
LaraCMS provides comprehensive user profile management with avatar uploads using Spatie Media Library, profile information updates, and email verification. Users can manage their profiles through dedicated Livewire components.
User Model Configuration
The User model integrates media handling at app/Models/User.php:17:
use Spatie\MediaLibrary\ HasMedia ;
use Spatie\MediaLibrary\ InteractsWithMedia ;
class User extends Authenticatable implements MustVerifyEmail , HasMedia
{
use HasFactory , HasRoles , Notifiable , InteractsWithMedia ;
}
The InteractsWithMedia trait enables avatar uploads and media management.
Profile Attributes
Fillable Fields
protected $fillable = [
'name' ,
'email' ,
'password' ,
];
Hidden Fields
protected $hidden = [
'password' ,
'remember_token' ,
];
Password and remember_token are always hidden from JSON serialization to prevent security leaks.
Field Casts
protected function casts () : array
{
return [
'email_verified_at' => 'datetime' ,
'password' => 'hashed' ,
];
}
Passwords are automatically hashed when assigned to the model.
Avatar Management
LaraCMS uses Spatie Media Library for avatar uploads with automatic image optimization.
Avatars are defined as a single-file collection at app/Models/User.php:68:
public function registerMediaCollections () : void
{
$this -> addMediaCollection ( 'avatars' ) -> singleFile ();
}
The singleFile() method ensures only one avatar per user - uploading a new avatar automatically deletes the previous one.
Image Conversions
Avatars are automatically resized for optimal performance at app/Models/User.php:74:
use Spatie\Image\Enums\ Fit ;
public function registerMediaConversions ( ? Media $media = null ) : void
{
$this
-> addMediaConversion ( 'preview' )
-> fit ( Fit :: Contain , 300 , 300 )
-> nonQueued ();
}
This creates a 300x300px preview version while maintaining aspect ratio.
The nonQueued() method processes images synchronously for immediate availability. For large-scale applications, remove this to queue image processing.
Uploading Avatars
// Add avatar
$user -> addMedia ( $request -> file ( 'avatar' ))
-> toMediaCollection ( 'avatars' );
// Get avatar URL
$avatarUrl = $user -> getFirstMediaUrl ( 'avatars' );
// Get preview conversion URL
$previewUrl = $user -> getFirstMediaUrl ( 'avatars' , 'preview' );
// Check if user has avatar
if ( $user -> hasMedia ( 'avatars' )) {
// User has uploaded an avatar
}
// Delete avatar
$user -> clearMediaCollection ( 'avatars' );
Avatar Display in Blade
@if ( $user -> hasMedia ( 'avatars' ))
< img src = " {{ $user -> getFirstMediaUrl ('avatars', 'preview') }} "
alt = " {{ $user -> name }} " >
@else
< div class = "avatar-initials" >
{{ $user -> initials () }}
</ div >
@endif
User Initials
For users without avatars, LaraCMS generates initials at app/Models/User.php:59:
public function initials () : string
{
return Str :: of ( $this -> name )
-> explode ( ' ' )
-> map ( fn ( string $name ) => Str :: of ( $name ) -> substr ( 0 , 1 ))
-> implode ( '' );
}
This method extracts the first letter of each word in the user’s name.
Examples
“John Doe” → “JD”
“Jane Smith Johnson” → “JSJ”
“Alice” → “A”
Use initials as a fallback when avatars aren’t uploaded to provide a personalized user experience.
Profile Updates
Users can update their profile information through the Settings profile component.
Profile Update Component
The update logic is in app/Livewire/Settings/Profile.php:29:
public function updateProfileInformation () : void
{
$user = Auth :: user ();
$validated = $this -> validate ([
'name' => [ 'required' , 'string' , 'max:255' ],
'email' => [
'required' ,
'string' ,
'lowercase' ,
'email' ,
'max:255' ,
Rule :: unique ( User :: class ) -> ignore ( $user -> id ),
],
]);
$user -> fill ( $validated );
if ( $user -> isDirty ( 'email' )) {
$user -> email_verified_at = null ;
}
$user -> save ();
$this -> dispatch ( 'profile-updated' , name : $user -> name );
}
Email Change Handling
When a user changes their email address, email_verified_at is set to null, requiring them to verify their new email address. This security measure prevents account takeover via email changes.
Re-verification Trigger
public function resendVerificationNotification () : void
{
$user = Auth :: user ();
if ( $user -> hasVerifiedEmail ()) {
$this -> redirectIntended ( default : route ( 'profile' , absolute : false ));
return ;
}
$user -> sendEmailVerificationNotification ();
Session :: flash ( 'status' , 'verification-link-sent' );
}
Profile Routes
Profile access is protected by authentication middleware:
Route :: prefix ( 'profile' )
-> middleware ( 'auth' , 'auth.session' )
-> group ( function () {
Route :: get ( '/' , [ ProfileController :: class , 'profile' ]) -> name ( 'profile' );
});
Middleware Protection
auth - Ensures user is authenticated
auth.session - Validates session integrity
Frontend Profile Component
The frontend profile display uses app/Livewire/Frontend/Profile.php:9:
class Profile extends Component
{
public $user ;
public $activeTab = 'profile' ;
public function mount ()
{
$this -> user = Auth :: user ();
}
public function setTab ( $tab )
{
$this -> activeTab = $tab ;
}
public function render ()
{
return view ( 'livewire.frontend.profile' , [
'user' => $this -> user ,
]);
}
}
This component supports tabbed navigation for different profile sections.
User Relationships
Links/URLs
Users can have multiple shortened URLs at app/Models/User.php:83:
public function links ()
{
return $this -> hasMany ( Link :: class );
}
This enables user-specific URL shortening and tracking.
Accessing User Links
// Get all user links
$links = $user -> links ;
// Get links count
$linkCount = $user -> links () -> count ();
// Get recent links
$recentLinks = $user -> links () -> latest () -> take ( 5 ) -> get ();
Profile Data Access
In Livewire Components
use Illuminate\Support\Facades\ Auth ;
public function mount ()
{
$this -> name = Auth :: user () -> name ;
$this -> email = Auth :: user () -> email ;
}
In Blade Templates
@auth
< p > Welcome, {{ auth () -> user () -> name }} ! </ p >
< p > Email: {{ auth () -> user () -> email }} </ p >
@if ( auth () -> user () -> hasVerifiedEmail ())
< span class = "badge badge-success" > Verified </ span >
@else
< span class = "badge badge-warning" > Not Verified </ span >
@endif
@endauth
In Controllers
public function show ()
{
$user = auth () -> user ();
return view ( 'profile' , [
'user' => $user ,
'avatarUrl' => $user -> getFirstMediaUrl ( 'avatars' , 'preview' ),
'initials' => $user -> initials (),
]);
}
Complete Profile Example
Here’s a complete example of profile management:
use App\Models\ User ;
use Illuminate\Support\Facades\ Auth ;
class ProfileController
{
public function update ( Request $request )
{
$user = Auth :: user ();
// Validate input
$validated = $request -> validate ([
'name' => 'required|string|max:255' ,
'email' => 'required|email|unique:users,email,' . $user -> id ,
'avatar' => 'nullable|image|max:2048' , // 2MB max
]);
// Update profile
$user -> update ([
'name' => $validated [ 'name' ],
'email' => $validated [ 'email' ],
]);
// Handle email change
if ( $user -> wasChanged ( 'email' )) {
$user -> email_verified_at = null ;
$user -> save ();
$user -> sendEmailVerificationNotification ();
}
// Handle avatar upload
if ( $request -> hasFile ( 'avatar' )) {
$user -> addMedia ( $request -> file ( 'avatar' ))
-> toMediaCollection ( 'avatars' );
}
return redirect () -> route ( 'profile' )
-> with ( 'success' , 'Profile updated successfully!' );
}
public function deleteAvatar ()
{
$user = Auth :: user ();
$user -> clearMediaCollection ( 'avatars' );
return back () -> with ( 'success' , 'Avatar deleted successfully!' );
}
}
Validation Rules
Name Validation
'name' => [ 'required' , 'string' , 'max:255' ]
Email Validation
'email' => [
'required' ,
'string' ,
'lowercase' , // Ensures email is stored in lowercase
'email' ,
'max:255' ,
Rule :: unique ( User :: class ) -> ignore ( $user -> id ), // Allows user to keep their current email
]
Avatar Validation
'avatar' => [
'nullable' ,
'image' , // Must be image file
'mimes:jpeg,jpg,png,gif' , // Allowed formats
'max:2048' , // Max 2MB
'dimensions:min_width=100,min_height=100' , // Minimum dimensions
]
File Upload Security:
Always validate file types and sizes
Store uploaded files outside the public directory
Use Spatie Media Library for automatic security measures
Set maximum file sizes to prevent storage abuse
Spatie Media Library handles file storage, organization, and conversions automatically.
Storage Organization
Media files are stored with the following structure:
storage/app/public/
└── [user_id]/
└── avatars/
├── original.jpg
└── conversions/
└── preview.jpg
// Get media model
$media = $user -> getFirstMedia ( 'avatars' );
// Get file information
$fileName = $media -> file_name ;
$fileSize = $media -> size ; // in bytes
$mimeType = $media -> mime_type ;
// Get URLs
$url = $media -> getUrl ();
$previewUrl = $media -> getUrl ( 'preview' );
// Download
$path = $media -> getPath ();
$content = file_get_contents ( $path );
Events and Notifications
Profile Updated Event
The profile component dispatches an event after updates:
$this -> dispatch ( 'profile-updated' , name : $user -> name );
Listen for this event in other Livewire components:
protected $listeners = [ 'profile-updated' => 'handleProfileUpdate' ];
public function handleProfileUpdate ( $name )
{
// Update UI with new name
$this -> userName = $name ;
}
Email Verification Notification
When email changes, verification notification is sent:
$user -> sendEmailVerificationNotification ();
Best Practices
Profile Management Tips:
Always require email verification after email changes
Use image conversions for different display sizes
Provide fallback initials when avatars aren’t uploaded
Validate and sanitize all user input
Use single-file media collections for avatars to prevent storage bloat
Process large images asynchronously with queues
Implement rate limiting for profile updates
Security Considerations:
Never expose sensitive fields (password, remember_token) in API responses
Require current password verification before allowing email changes
Implement CSRF protection on all profile update forms
Sanitize file names and validate file types
Set appropriate file size limits
Store uploaded files outside the web root
Next Steps
Authentication Learn about user authentication and registration flows
Roles & Permissions Understand role-based access control with Spatie Permission