Skip to content

Commit

Permalink
implement
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Jun 6, 2020
1 parent 31be534 commit 9a4817b
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 122 deletions.
41 changes: 41 additions & 0 deletions src/Core.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace atk4\core;

final class Core
{
/** @var Factory */
private static $_factory;

private function __construct()
{
// zeroton
}

protected static function getFactory(): Factory
{
if (self::$_factory === null) {
self::$_factory = new Factory();
}

return self::$_factory;
}

/**
* See \atk4\core\Factory::mergeSeeds().
*/
public static function mergeSeeds(...$seeds)
{
return static::getFactory()->mergeSeeds(...$seeds);
}

/**
* See \atk4\core\Factory::factory().
*/
public static function factory($seed, $defaults = [], /* remove in 2021-jun, catch passed but no longer supported prefix */...$extraArgs): object
{
return static::getFactory()->factory($seed, $defaults, ...$extraArgs);
}
}
63 changes: 51 additions & 12 deletions src/DIContainerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ protected function setMissingProperty($key, $value)
}

/**
* Return the argument and check if it is instance of current class. Typehinting-friendly.
* Return the argument and assert it is instance of current class.
*
* Best way to annotate object type if it not defined as function parameter or strong typing can not be used.
* The best, typehinting-friendly, way to annotate object type if it not defined
* at method header or strong typing in method header can not be used.
*
* @return static
*/
Expand All @@ -108,29 +109,67 @@ public static function assertInstanceOf(object $object)// :static supported by P
return $object;
}

private static function _fromSeedPrecheck($seed, bool $unsafe)// :self is too strict with unsafe behaviour
{
if (!is_object($seed)) {
if (!is_array($seed)) {
if (!is_string($seed)) { // allow string class name seed but prevent bad usage
throw (new Exception('Seed must be an array, a string class name (deprecated) or an object'))
->addMoreInfo('seed_type', gettype($seed))
->toError(\TypeError::class);
}

$seed = [$seed];
}

if (!isset($seed[0])) {
throw (new Exception('Class name is not defined in seed'))
->toError(\TypeError::class);
}

$cl = $seed[0];
if (!$unsafe && !is_a($cl, static::class, true)) {
throw (new Exception('Seed class is not a subtype of ' . static::class))
->addMoreInfo('seed_class', $cl)
->toError(\TypeError::class);
}
}

return $seed;
}

/**
* Create new object and check if it is instance of current class. Typehinting-friendly.
* Create new object from seed and assert it is instance of current class.
*
* Best way to create object if it should not be immediatelly added to a parent (otherwise use addTo()).
* The best, typehinting-friendly, way to create an object if it should not be
* immediately added to a parent (otherwise use addTo() method).
*
* @param array|string $seed
* @param array|string $seed The first element specifies a class name, other element are seed
*
* @return static
*/
public static function fromSeed($seed = [])// :static supported by PHP8+
{// @TODO move code from addTo here
return static::addTo(Shared::getFactory(), $seed, [], true);
public static function fromSeed($seed = [], $defaults = [])// :static supported by PHP8+
{
$seed = static::_fromSeedPrecheck($seed, false);
$object = Core::factory($seed);

static::assertInstanceOf($object);

return $object;
}

/**
* Same as ::fromSeed(), but the first element of seed specifies a class name instead of static::class.
* Same as fromSeed(), but the new object is not asserted to be an instance of this class.
*
* @param array|string $seed The first element specifies a class name, other element are seed
*
* @return static
*/
public static function fromSeedWithCl($seed = [])// :static supported by PHP8+
{// @TODO move code from addTo here
return static::addToWithCl(Shared::getFactory(), $seed, [], true);
public static function fromSeedUnsafe($seed = [], $defaults = [])// :self is too strict with unsafe behaviour
{
$seed = static::_fromSeedPrecheck($seed, true);
$object = Core::factory($seed);

return $object;
}
}
21 changes: 13 additions & 8 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ public function mergeSeeds($seed, $seed2, ...$more_seeds)
return $res;
}

protected function createNewObject(string $className, array $ctorArgs): object
{
return new $className(...$ctorArgs);
}

/**
* Given a Seed (see doc) as a first argument, will create object of a corresponding
* class, call constructor with numerical arguments of a seed and inject key/value
Expand All @@ -114,14 +119,13 @@ public function mergeSeeds($seed, $seed2, ...$more_seeds)
*
* To learn more about mechanics of factory trait, see documentation
*
* @param mixed $seed
* @param array $defaults
* @param string $prefix No longer supported
* @param mixed $seed
* @param array $defaults
*/
public function factory($seed, $defaults = [], string $prefix = null): object
public function factory($seed, $defaults = []): object
{
if ($prefix !== null) { // remove in 2021-june
throw new Exception(['Factory does no longer support relative names, pass full class name without prefix']);
if (func_num_args() > 2) { // prevent bad usage
throw new \Error('Too many method arguments');
}

if ($defaults === null) {
Expand All @@ -144,7 +148,8 @@ public function factory($seed, $defaults = [], string $prefix = null): object
$seed = $this->mergeSeeds($seed, $defaults);

if (is_object($seed)) {
// setDefaults already called
// setDefaults() already called in mergeSeeds()

return $seed;
}

Expand All @@ -160,7 +165,7 @@ public function factory($seed, $defaults = [], string $prefix = null): object
]);
}

$object = new $object(...$arguments);
$object = $this->createNewObject($object, $arguments);
}

if ($injection) {
Expand Down
10 changes: 7 additions & 3 deletions src/FactoryTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ trait FactoryTrait
*
* @deprecated will be removed in 2021-jun
*/
public function mergeSeeds($seed, $seed2, ...$more_seeds)
public function mergeSeeds(...$seeds)
{
return Shared::getFactory()->mergeSeeds($seed, $seed2, $more_seeds);
return Core::mergeSeeds(...$seeds);
}

/**
Expand All @@ -33,6 +33,10 @@ public function mergeSeeds($seed, $seed2, ...$more_seeds)
*/
public function factory($seed, $defaults = []): object
{
return Shared::getFactory()->factory($seed, $defaults);
if (func_num_args() > 2) { // prevent bad usage
throw new \Error('Too many method arguments, factory does no longer support prefix');
}

return Core::factory($seed, $defaults);
}
}
28 changes: 0 additions & 28 deletions src/Shared.php

This file was deleted.

99 changes: 28 additions & 71 deletions src/StaticAddToTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
*/
trait StaticAddToTrait
{
// use DIContainerTrait; // uncomment once PHP7.2 support is dropped
// enable for develop only! remove before merge!
/**/ use DIContainerTrait; // uncomment once PHP7.2 support is dropped

/**
* Check this property to see if trait is present in the object.
Expand All @@ -20,9 +21,18 @@ trait StaticAddToTrait
*/
public $_staticAddToTrait = true;

private static function _addTo_add(object $parent, object $object, array $addArgs, bool $skipAdd = false): void
{
if (!$skipAdd) {
$parent->add($object, ...$addArgs);
}
}

/**
* A better way to initialize and add new object into parent - more typehinting-friendly.
* The new object is checked if it is instance of current class.
* Initialize and add new object into parent. The new object is asserted to be an instance of current class.
*
* The best, typehinting-friendly, way to create an object if it should be immediately
* added to a parent (otherwise use fromSeed() method).
*
* $crud = CRUD::addTo($app, ['displayFields' => ['name']]);
* is equivalent to
Expand All @@ -33,11 +43,9 @@ trait StaticAddToTrait
*
* @return static
*/
public static function addTo(object $parent, $seed = [], array $add_args = [], bool $skip_add = false)// :static supported by PHP8+
public static function addTo(object $parent, $seed = [], array $addArgs = [], bool $skipAdd = false)// :static supported by PHP8+
{
if (is_object($seed)) {
$object = $seed;
} else {
if (!is_object($seed)) {
if (!is_array($seed)) {
if (!is_scalar($seed)) { // allow single element seed but prevent bad usage
throw (new Exception('Seed must be an array or a scalar'))
Expand All @@ -47,29 +55,11 @@ public static function addTo(object $parent, $seed = [], array $add_args = [], b

$seed = [$seed];
}

if (isset($parent->_factoryTrait)) {
$object = $parent->factory(static::class, $seed);
} else {
$object = new static(...$seed);
}
}

return static::_addTo_add($parent, $object, false, $add_args, $skip_add);
}

/**
* @return static
*/
private static function _addTo_add(object $parent, object $object, bool $unsafe, array $add_args, bool $skip_add = false)
{
if (!$unsafe) {
static::checkInstanceOf($object);
}
$object = static::fromSeed(static::class, $seed);

if (!$skip_add) {
$parent->add($object, ...$add_args);
}
static::_addTo_add($parent, $object, $addArgs, $skipAdd);

return $object;
}
Expand All @@ -81,61 +71,28 @@ private static function _addTo_add(object $parent, object $object, bool $unsafe,
*
* @return static
*/
public static function addToWithCl(object $parent, $seed = [], array $add_args = [], bool $skip_add = false)// :static supported by PHP8+
public static function addToWithCl(object $parent, $seed = [], array $addArgs = [], bool $skipAdd = false)// :static supported by PHP8+
{
return static::_addToWithCl($parent, $seed, false, $add_args, $skip_add);
$object = static::fromSeed(static::class, $seed);

static::_addTo_add($parent, $object, $addArgs, $skipAdd);

return $object;
}

/**
* Same as addToWithCl(), but the new object is not checked if it is instance of this class.
* Same as addToWithCl(), but the new object is not asserted to be an instance of this class.
*
* @param array|string $seed The first element specifies a class name, other element are seed
*
* @return static
*/
public static function addToWithClUnsafe(object $parent, $seed = [], array $add_args = [], bool $skip_add = false)// :self is too strict with unsafe behaviour
{
return static::_addToWithCl($parent, $seed, true, $add_args, $skip_add);
}

/**
* @return static
*/
private static function _addToWithCl(object $parent, $seed, bool $unsafe, array $add_args, bool $skip_add = false)
public static function addToWithClUnsafe(object $parent, $seed = [], array $addArgs = [], bool $skipAdd = false)// :self is too strict with unsafe behaviour
{
if (is_object($seed)) {
$object = $seed;
} else {
if (!is_array($seed)) {
if (!is_scalar($seed)) { // allow single element seed but prevent bad usage
throw (new Exception('Seed must be an array or a scalar'))
->addMoreInfo('seed_type', gettype($seed))
->toError(\TypeError::class);
}
$object = static::fromSeedUnsafe(static::class, $seed);

$seed = [$seed];
}

if (!isset($seed[0])) {
throw (new Exception('Class name in seed is not defined'))
->toError(\TypeError::class);
}

$cl = $seed[0];
if (!$unsafe && !is_a($cl, static::class, true)) {
throw (new Exception('Seed class is not a subtype of ' . static::class))
->addMoreInfo('seed_class', $cl)
->toError(\TypeError::class);
}
static::_addTo_add($parent, $object, $addArgs, $skipAdd);

if (isset($parent->_factoryTrait)) {
$object = $parent->factory($seed);
} else {
unset($seed[0]);
$object = new $cl(...$seed);
}
}

return static::_addTo_add($parent, $object, $unsafe, $add_args, $skip_add);
return $object;
}
}

0 comments on commit 9a4817b

Please sign in to comment.