@@ -328,6 +328,173 @@ class Breakfast_Model extends Model {
328328}
329329``` 
330330
331+ ## Model Relationships  
332+ 
333+ Models can define relationships to other models, similar to how properties are defined. Relationships support lazy loading and caching.
334+ 
335+ ### Defining Relationships  
336+ 
337+ Relationships can be defined using either shorthand syntax or the fluent ` ModelRelationshipDefinition `  API:
338+ 
339+ #### Using shorthand syntax:  
340+ 
341+ ``` php 
342+ namespace Boomshakalaka\Whatever;
343+ 
344+ use Boomshakalaka\StellarWP\Models\Model;
345+ use Boomshakalaka\StellarWP\Models\ValueObjects\Relationship;
346+ 
347+ class Product_Model extends Model {
348+ 	/**
349+ 	 * @inheritDoc
350+ 	 */
351+ 	protected static $relationships = [
352+ 		'category' => Relationship::BELONGS_TO,
353+ 		'reviews' => Relationship::HAS_MANY,
354+ 		'tags' => Relationship::MANY_TO_MANY,
355+ 	];
356+ 
357+ 	/**
358+ 	 * Define how to load the category relationship.
359+ 	 */
360+ 	protected function category() {
361+ 		return Category_Model::query()->where('id', $this->category_id);
362+ 	}
363+ 
364+ 	/**
365+ 	 * Define how to load the reviews relationship.
366+ 	 */
367+ 	protected function reviews() {
368+ 		return Review_Model::query()->where('product_id', $this->id);
369+ 	}
370+ 
371+ 	/**
372+ 	 * Define how to load the tags relationship.
373+ 	 */
374+ 	protected function tags() {
375+ 		return Tag_Model::query()
376+ 			->select('tags.*')
377+ 			->join('product_tags', 'product_tags.tag_id', 'tags.id')
378+ 			->where('product_tags.product_id', $this->id);
379+ 	}
380+ }
381+ ``` 
382+ 
383+ #### Using relationship definitions for more control:  
384+ 
385+ ``` php 
386+ namespace Boomshakalaka\Whatever;
387+ 
388+ use Boomshakalaka\StellarWP\Models\Model;
389+ use Boomshakalaka\StellarWP\Models\ModelRelationshipDefinition;
390+ 
391+ class Product_Model extends Model {
392+ 	/**
393+ 	 * @inheritDoc
394+ 	 */
395+ 	protected static function relationships(): array {
396+ 		return [
397+ 			'category' => (new ModelRelationshipDefinition('category'))
398+ 				->belongsTo(),
399+ 			'reviews' => (new ModelRelationshipDefinition('reviews'))
400+ 				->hasMany(),
401+ 			'tags' => (new ModelRelationshipDefinition('tags'))
402+ 				->manyToMany()
403+ 				->disableCaching(), // Don't cache this relationship
404+ 		];
405+ 	}
406+ 
407+ 	// Define relationship loaders as above...
408+ }
409+ ``` 
410+ 
411+ ### Relationship Types  
412+ 
413+ Five relationship types are available:
414+ 
415+ -  ` Relationship::HAS_ONE `  - Model has one related model
416+ -  ` Relationship::HAS_MANY `  - Model has many related models
417+ -  ` Relationship::BELONGS_TO `  - Model belongs to another model
418+ -  ` Relationship::BELONGS_TO_MANY `  - Model belongs to many related models
419+ -  ` Relationship::MANY_TO_MANY `  - Many-to-many relationship
420+ 
421+ ### Accessing Relationships  
422+ 
423+ Relationships are loaded lazily when accessed as properties:
424+ 
425+ ``` php 
426+ $product = Product_Model::find(1);
427+ 
428+ // First access loads from database and caches result
429+ $category = $product->category;
430+ 
431+ // Subsequent accesses use cached value (if caching enabled)
432+ $category = $product->category; // No additional query
433+ 
434+ // Access multiple relationship
435+ $reviews = $product->reviews; // Returns array of Review_Model instances
436+ ``` 
437+ 
438+ ### Relationship Caching  
439+ 
440+ By default, relationships are cached after the first load. You can control caching behavior:
441+ 
442+ ``` php 
443+ class Product_Model extends Model {
444+ 	protected static function relationships(): array {
445+ 		return [
446+ 			// Cached (default)
447+ 			'category' => (new ModelRelationshipDefinition('category'))
448+ 				->belongsTo(),
449+ 
450+ 			// Not cached - always loads fresh
451+ 			'stock' => (new ModelRelationshipDefinition('stock'))
452+ 				->hasOne()
453+ 				->disableCaching(),
454+ 		];
455+ 	}
456+ }
457+ ``` 
458+ 
459+ ### Managing Relationship Cache  
460+ 
461+ Models provide methods to manage relationship caching:
462+ 
463+ ``` php 
464+ $product = Product_Model::find(1);
465+ 
466+ // Manually set a cached relationship value
467+ $product->setCachedRelationship('category', $newCategory);
468+ 
469+ // Clear a specific relationship cache
470+ $product->purgeRelationship('category');
471+ $category = $product->category; // Reloads from database
472+ 
473+ // Clear all relationship caches
474+ $product->purgeRelationshipCache();
475+ ``` 
476+ 
477+ ### Customizing Relationship Loading  
478+ 
479+ Override the ` fetchRelationship() `  method to customize how relationships are loaded:
480+ 
481+ ``` php 
482+ class Product_Model extends Model {
483+ 	/**
484+ 	 * Custom relationship loading logic.
485+ 	 */
486+ 	protected function fetchRelationship(string $key) {
487+ 		// Add custom logic before loading
488+ 		if ($key === 'category' && !$this->category_id) {
489+ 			return null;
490+ 		}
491+ 
492+ 		// Default loading behavior
493+ 		return parent::fetchRelationship($key);
494+ 	}
495+ }
496+ ``` 
497+ 
331498## Attribute validation  
332499
333500Sometimes it would be helpful to validate attributes that are set in the model. To do that, you can create ` validate_*() ` 
0 commit comments