Source browser » Mondoc
Explore the source behind \District5\Mondoc\Db\Model\MondocAbstractSubModel
View source: [ raw ] [ highlight ]
View on GitHub open_in_newBelow is the content for the selected file.
Class: \District5\Mondoc\Db\Model\MondocAbstractSubModel
<?php
/**
* District5 Mondoc Library
*
* @author District5 <hello@district5.co.uk>
* @copyright District5 <hello@district5.co.uk>
* @link https://www.district5.co.uk
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace District5\Mondoc\Db\Model;
use DateTime;
use District5\Mondoc\Db\Model\Traits\ExcludedPropertiesTrait;
use District5\Mondoc\Db\Model\Traits\FieldAliasMapTrait;
use District5\Mondoc\Db\Model\Traits\MondocNestedModelTrait;
use District5\Mondoc\Db\Model\Traits\UnmappedPropertiesTrait;
use District5\Mondoc\Helper\MondocTypes;
use MongoDB\Model\BSONArray;
use MongoDB\Model\BSONDocument;
/**
* Abstract class MondocAbstractSubModel.
*
* @package District5\Mondoc\Db\Model
*/
abstract class MondocAbstractSubModel
{
use ExcludedPropertiesTrait;
use FieldAliasMapTrait;
use MondocNestedModelTrait;
use UnmappedPropertiesTrait;
/**
* MondocAbstractSubModel constructor.
*/
public function __construct()
{
$this->initMondocNestedModels();
$this->initMondocFieldAliases();
}
/**
* Inflate an array of DTOs from an array of arrays containing data.
*
* @param array $data
*
* @return $this[]
*
* @example
* MyModel::inflateMultipleArrays(
* [
* [
* 'name' => 'Joe',
* 'age' => 30
* ],
* [
* 'name' => 'Jane',
* 'age' => 32
* ]
* ]
* )
*/
public static function inflateMultipleArrays(array $data): array
{
if (empty($data)) {
return [];
}
$cl = get_called_class();
/* @var $cl MondocAbstractSubModel - it's not really. */
$final = [];
foreach ($data as $datum) {
if ($datum instanceof BSONDocument) {
$datum = $datum->getArrayCopy();
}
$inst = $cl::inflateSingleArray($datum);
$inst->assignDefaultVars();
$final[] = $inst;
}
return $final;
}
/**
* Assign any default variables to this model.
*/
protected function assignDefaultVars(): void
{
}
/**
* Inflate a DTO from an array of data.
*
* @param array $data
*
* @return $this
*/
public static function inflateSingleArray(array $data): static
{
$cl = get_called_class();
$inst = new $cl();
/* @var $inst MondocAbstractSubModel */
foreach ($data as $k => $v) {
if (is_int($k)) {
continue;
}
if (in_array($k, $inst->getPropertyExclusions())) {
continue;
}
$k = $inst->getFieldAliasSingleMap($k, false);
$isNestedAny = $inst->isMondocNestedAnyType($k);
if ((is_array($v) || is_object($v)) && $isNestedAny === true) {
$subClassName = $inst->getMondocNestedClassName($k);
$isMulti = $inst->isMondocNestedMultipleObjects($k);
if (is_object($v)) {
$v = MondocTypes::arrayToPhp($v);
}
/* @var $subClassName MondocAbstractSubModel */
if ($isMulti === true) {
$v = $subClassName::inflateMultipleArrays($v);
} else {
$v = $subClassName::inflateSingleArray($v);
}
}
if ($isNestedAny === false && ($v instanceof BSONDocument || $v instanceof BSONArray)) {
$v = $v->getArrayCopy();
}
$inst->__set($k, $v);
}
return $inst;
}
/**
* Helper method to convert an object (with potential arrays or objects inside) into a normal array.
*
* @param object $obj
*
* @return array
*/
protected static function objectToArray(object $obj): array
{
$props = get_object_vars($obj);
$array = [];
foreach ($props as $k => $v) {
if (is_array($v)) {
$v = self::arrayToArray($v);
}
if (is_object($v)) {
$v = self::objectToArray($v);
}
$array[$k] = $v;
}
return $array;
}
/**
* Helper method to convert an array (with potential objects) into a normal array.
*
* @param array $arr
*
* @return array
*/
protected static function arrayToArray(array $arr): array
{
$data = [];
$isIntArray = false;
$i = 0;
foreach ($arr as $k => $v) {
if ($k === $i) {
$isIntArray = true;
}
if (is_array($v)) {
$v = self::arrayToArray($v);
}
if (is_object($v)) {
$v = self::objectToArray($v);
}
if (true === $isIntArray) {
$data[] = $v;
} else {
$data[$k] = $v;
}
++$i;
}
return $data;
}
/**
* Get a value via magic method.
*
* @param string $name
*
* @return null|mixed
*/
public function __get(string $name)
{
if (property_exists($this, $name)) {
return $this->{$name};
}
if (array_key_exists($name, $this->_mondocUnmapped)) {
return $this->_mondocUnmapped[$name];
}
return null;
}
/**
* Set a value via magic method.
*
* @param string $name
* @param mixed $value
* @return void
*/
public function __set(string $name, mixed $value): void
{
if (property_exists($this, $name)) {
$this->{$name} = $value;
return;
}
$this->_mondocUnmapped[$name] = $value;
}
/**
* Magic method to echo the class name if accidentally used as a string.
*
* @return string
*/
public function __toString(): string
{
return get_class($this);
}
/**
* Get an array export representation of this model and all child models.
*
* @return array
*/
public function asArray(): array
{
$data = [];
foreach ($this->getMondocObjectVars() as $originalK => $v) {
$k = $this->getFieldAliasSingleMap($originalK, true);
if ($this->isMondocNestedAnyType([$k, $originalK]) === true) {
if ($this->isMondocNestedMultipleObjects([$k, $originalK]) === true) {
/* @var $v MondocAbstractSubModel[] */
$subs = [];
foreach ($v as $datum) {
if ($datum instanceof MondocAbstractSubModel) {
$subs[] = $datum->asArray();
}
}
$v = $subs;
} else {
if ($v instanceof MondocAbstractSubModel) {
/* @var $v MondocAbstractSubModel */
$v = $v->asArray();
}
}
} elseif ($v instanceof DateTime) {
$v = MondocTypes::phpDateToMongoDateTime($v);
}
$data[$k] = $v;
}
if ($this->hasUnmappedProperties() === true) {
$data = array_merge_recursive($this->_mondocUnmapped, $data);
}
return $data;
}
/**
* Export the model as a JSON encodable array, omitting certain fields.
*
* @param array $omitKeys (optional) fields to omit.
* @return array
*/
public function asJsonEncodableArray(array $omitKeys = []): array
{
$data = MondocTypes::typeToJsonFriendly(
$this->asArray()
);
foreach ($omitKeys as $o) {
unset($data[$o]);
}
return $data;
}
/**
* @return array
*/
public function getMondocObjectVars(): array
{
$vars = get_object_vars($this);
$ignore = $this->getPropertyExclusions();
foreach ($ignore as $i) {
unset($vars[$i]);
}
return $vars;
}
/**
* @return bool
*/
public function isVersionableModel(): bool
{
return false;
}
/**
* Does the model contain this revision number trait?
*
* @return bool
*/
public function isRevisionNumberModel(): bool
{
return false;
}
/**
* @return bool
*/
public function isMondocModel(): bool
{
return false;
}
/**
* @return bool
*/
public function isMondocSubModel(): bool
{
return true;
}
}