/** * Set a property of an Eloquent model, normal object or array * @param mixed $objectOrArray model, object or array * @param string $property * @param void */ public static function setProperty(&$objectOrArray, $property, $value) { // Eloquent models are also instances of ArrayAccess, and therefore // we check for that first if ($objectOrArray instanceof EloquentModel) { // Does relation exist? // If so, only set the relation if not primitive. Keeping a attribute // as a relation will allow for it to be converted to arrays during // serialization if ($property) { if ($objectOrArray->relationLoaded($property) && !Utility::isPrimitive($value)) { $objectOrArray->setRelation($property, $value); // If attribute is not a relation we just set it on // the model directly. If it is a primitive relation (a relation // converted to IDs) we unset the relation and set it as an attribute } else { unset($objectOrArray[$property]); $objectOrArray->setAttribute($property, $value); } } } elseif (is_array($objectOrArray)) { $objectOrArray[$property] = $value; } else { $objectOrArray->{$property} = $value; } }
/** * Map through the collection and convert it to a collection * of ids * @param string $property * @param object $object * @param array $root * @param string $fullPropertyPath * @return mixed */ public function resolve($property, &$object, &$root, $fullPropertyPath) { if (is_array($object)) { // We need to determine if this is a singular relationship or // a collection of models $arrayCopy = $object; $firstElement = array_shift($arrayCopy); // The object was not a collection, and was rather a single // model, because the first item returned was a property // We therefore just return the single ID if (Utility::isPrimitive($firstElement)) { return (int) Utility::getProperty($object, 'id'); } return array_map(function ($entry) { return (int) Utility::getProperty($entry, 'id'); }, $object); } elseif ($object instanceof Collection) { return $object->map(function ($entry) { return (int) Utility::getProperty($entry, 'id'); }); // The relation is not a collection, but rather // a singular relation } elseif ($object instanceof Model) { return $object->id; } }
/** * Parse a single resource using given modes * @param array $modes * @param mixed $resource * @param array $root * @param string $fullPropertyPath * @return mixed */ private function parseResource(array $modes, &$resource, &$root, $fullPropertyPath = '') { foreach ($modes as $relation => $mode) { $modeResolver = $this->resolveMode($mode); $steps = explode('.', $relation); // Get the first resource in the relation // TODO: Refactor $property = array_shift($steps); if (is_array($resource)) { if ($resource[$property] === null) { continue; } $object =& $resource[$property]; } else { if ($resource->{$property} === null) { continue; } $object =& $resource->{$property}; } if (empty($steps)) { // This is the deepest level. Resolve it. $fullPropertyPath .= $relation; $object = $this->modeResolvers[$mode]->resolve($relation, $object, $root, $fullPropertyPath); } else { // More levels exist in this relation. // We want a drill down and resolve the deepest level first. $path = implode('.', $steps); $modes = [$path => $mode]; // Add the previous levels to the full path so it can be used // to populate the root level properly. $fullPropertyPath .= $property . '.'; if (Utility::isCollection($object)) { $object = $this->parseCollection($modes, $object, $root, $fullPropertyPath); } else { $object = $this->parseResource($modes, $object, $root, $fullPropertyPath); } } // Reset the full property path after running a full relation $fullPropertyPath = ''; Utility::setProperty($resource, $property, $object); } return $resource; }
/** * Check if the resource already exists in the root collection by id * TODO: https://github.com/esbenp/laravel-controller/issues/2 * @param mixed $collection * @param mixed $resource */ private function addResourceToRootCollectionIfNonExistant(&$collection, $resource) { $identifier = Utility::getProperty($resource, 'id'); $exists = false; $copy = $collection instanceof Collection ? $collection->toArray() : $collection; foreach ($copy as $rootResource) { if ((int) Utility::getProperty($rootResource, 'id') === (int) $identifier) { $exists = true; break; } } if ($exists === false) { if (is_array($collection)) { $collection[] = $resource; } elseif ($collection instanceof Collection) { $collection->push($resource); } } }