<?php

namespace Limb_Chatbot\Includes\Services;

use ReflectionClass;


/**
 * A specialized collection class for data objects that supports lazy relation loading.
 *
 * This extends the base `Collection` class and provides the ability to include related properties
 * dynamically via reflection and method calls on the data objects.
 *
 * @since 1.0.0
 */
class Data_Object_Collection extends Collection {

	/**
	 * Load specified relation(s) onto each object in the collection.
	 *
	 * @since 1.0.0
	 *
	 * @param string|array $relations One or more relation method names to load.
	 * @param array        $args      Optional arguments passed to each relation method.
	 * @return static
	 */
	public function with( $relations, $args = [] ) {
		if ( $this->is_empty() || empty( $relations ) ) {
			return $this;
		}
		if ( is_array( $relations ) ) {
			foreach ( $relations as $item ) {
				$this->include_property( $item, $args );
			}
		} else {
			$this->include_property( $relations, $args );
		}

		return $this;
	}

	/**
	 * Includes the specified relation property for each item in the collection.
	 *
	 * This uses reflection to verify the relation method exists, and populates the `included` property
	 * of each object if supported.
	 *
	 * @since 1.0.0
	 *
	 * @param string $relation Name of the relation method to include.
	 * @param array  $args     Optional arguments passed to the relation method.
	 * @return void
	 */
	private function include_property( $relation, $args ) {
		$data_object = new ReflectionClass( get_class( $this->first() ) );
		if ( method_exists( $data_object->getName(), $relation ) ) {
			foreach ( $this->items as $key => $item ) {
				if ( property_exists( $this->items[ $key ], 'included' ) ) {
					if ( ! empty( $args ) ) {
						$this->items[ $key ]->included[ $relation ] = $this->items[ $key ]->{$relation}( $args );
					} else {
						$this->items[ $key ]->included[ $relation ] = $this->items[ $key ]->{$relation}();
					}
				}
			}
		}
	}
}