add todos from github

This commit is contained in:
Dennis Eichhorn 2019-12-31 19:54:35 +01:00
parent 41bca90452
commit 4414fad940
40 changed files with 421 additions and 229 deletions

View File

@ -21,6 +21,10 @@ namespace phpOMS\Account;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#200
* Implement remove permission functionality
* Currently only adding permissions is possible but it should also be possible to remove permissions from an account.
*/
trait PermissionHandlingTrait
{
@ -136,7 +140,7 @@ trait PermissionHandlingTrait
int $element = null,
int $component = null
) : bool {
$app = $app !== null ? \strtolower($app) : $app; // @todo: maybe don't do this because this function get's called so often.
$app = $app !== null ? \strtolower($app) : $app;
for ($i = 0; $i < $this->pLength; ++$i) {
if ($this->permissions[$i]->hasPermission($permission, $unit, $app, $module, $type, $element, $component)) {

View File

@ -193,7 +193,8 @@ class ApplicationAbstract
*
* @return void
*
* @todo replace with proper setter (faster)
* @todo Orange-Management/phpOMS#218
* As soon as readonly member variables are possible the magic methods should be removed.
*
* @since 1.0.0
*/
@ -213,7 +214,8 @@ class ApplicationAbstract
*
* @return mixed Returns the value of the application member
*
* @todo replace with proper getter (faster)
* @todo Orange-Management/phpOMS#218
* As soon as readonly member variables are possible the magic methods should be removed.
*
* @since 1.0.0
*/

View File

@ -23,6 +23,20 @@ use phpOMS\DataStorage\DataStorageConnectionInterface;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#184
* Add more functions:
* * exists - Checks if the key exists
* * getLike - Get all by pattern
* * removeLike - Remove all by pattern
* * getMult - Get multiple results
* * removeMult - Remove multiple
* * setMult - Set multiple
* * updateExpiration - Update expiration
* * increment - Increment numeric value
* * decrement - Decrement numeric value
* * rename - Rename key
* * save - Save cache (to hard drive or somewhere else)
*/
interface ConnectionInterface extends DataStorageConnectionInterface
{

View File

@ -39,6 +39,14 @@ use phpOMS\System\File\Local\File;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#182
* Create file locking
* The file caching should implement a locking solution for the cache files.
* Without it a different process may try to read it while the cache is still getting created.
* A solution could be to create a directory or file called _lock which is getting checked
* (if this file exists reading from cache, modifying or creating it is not allowed except the _lock file is 5 minutes or so old).
* File and or directory creation should be atomic, right?
*/
final class FileCache extends ConnectionAbstract
{

View File

@ -43,8 +43,6 @@ interface DataStorageConnectionInterface
*
* @return void
*
* @todo make private, reason was that not everyone wants to connect during initialization?!
*
* @since 1.0.0
*/
public function connect(array $data) : void;

View File

@ -29,6 +29,11 @@ use phpOMS\DataStorage\Database\Schema\Grammar\Grammar as SchemaGrammar;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/Modules#100
* Init only when used
* The database connection should only get initialized when used.
* Setup happens before but initialization should only happen on the first usage.
*/
abstract class ConnectionAbstract implements ConnectionInterface
{

View File

@ -47,7 +47,14 @@ final class MysqlConnection extends ConnectionAbstract
$this->type = DatabaseType::MYSQL;
$this->grammar = new MysqlGrammar();
$this->schemaGrammar = new MysqlSchemaGrammar();
$this->connect($dbdata); // todo: remove since this is a side effect that doesn't belong to constructor
/**
* @todo Orange-Management/phpOMS#219
* Don't automatically connect to the database during initialization. This should be done in a separate step.
* This also requires to adjust some other framework code which currently expects the database connection to be established after initialization.
* Sometimes DB connections may not be needed and should only be connected to once required.
*/
$this->connect($dbdata);
}
/**

View File

@ -47,7 +47,14 @@ final class PostgresConnection extends ConnectionAbstract
$this->type = DatabaseType::PGSQL;
$this->grammar = new PostgresGrammar();
$this->schemaGrammar = new PostgresSchemaGrammar();
$this->connect($dbdata); // todo: remove since this is a side effect that doesn't belong to constructor
/**
* @todo Orange-Management/phpOMS#219
* Don't automatically connect to the database during initialization. This should be done in a separate step.
* This also requires to adjust some other framework code which currently expects the database connection to be established after initialization.
* Sometimes DB connections may not be needed and should only be connected to once required.
*/
$this->connect($dbdata);
}
/**

View File

@ -47,6 +47,13 @@ final class SQLiteConnection extends ConnectionAbstract
$this->type = DatabaseType::SQLITE;
$this->grammar = new SQLiteGrammar();
$this->schemaGrammar = new SQLiteSchemaGrammar();
/**
* @todo Orange-Management/phpOMS#219
* Don't automatically connect to the database during initialization. This should be done in a separate step.
* This also requires to adjust some other framework code which currently expects the database connection to be established after initialization.
* Sometimes DB connections may not be needed and should only be connected to once required.
*/
$this->connect($dbdata);
}

View File

@ -47,6 +47,13 @@ final class SqlServerConnection extends ConnectionAbstract
$this->type = DatabaseType::SQLSRV;
$this->grammar = new MysqlGrammar();
$this->schemaGrammar = new MysqlSchemaGrammar();
/**
* @todo Orange-Management/phpOMS#219
* Don't automatically connect to the database during initialization. This should be done in a separate step.
* This also requires to adjust some other framework code which currently expects the database connection to be established after initialization.
* Sometimes DB connections may not be needed and should only be connected to once required.
*/
$this->connect($dbdata);
}

View File

@ -31,7 +31,106 @@ use Throwable;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
* @todo: currently hasmany, owns one etc. are not using joins. In some cases this could improve the performance instead of separately querying the database
*
* @todo Orange-Management/phpOMS#220
* Use joins.
* The datamapper is not using any joins currently which could significantly improve the performance of the queries.
* Joins should be used for:
* * composite models (models built from multiple tables)
* * owns one
* * has one
* * belongs to one
* * conditionals
*
* @todo Orange-Management/phpOMS#222
* Implement conditionals.
* Conditionals are hardcoded or dynamically passed parameters based on which a model is found.
* The best example is the language of a model (e.g. news article), which is stored as foreign key in the model.
* With conditionals it's possible to reference other tables and also return elements based on the value in these tables/columns.
* Possible solution:
* 1. join tables/columns which have conditionals
* 2. perform the select based on the match
* ```php
* TestMapper::getByConditional(['l11n' => 'en']);
* ```
*
* @todo Orange-Management/phpOMS#73
* Implement extending
* Allow a data mapper to extend another data mapper.
* This way the object will be inserted first with one data mapper and the remaining fields will be filled by the extended data mapper.
* How can wen solve a mapper extending a mapper ... extending a mapper?
*
* @todo Orange-Management/phpOMS#102
* Solve N+1 problem
* Currently the datamapper generates separate queries for objects that have relationships defined.
* Most of these relationships could be defined MUCH smarter and reduce the amout of sub-queries e.g. selecting a task and all its comments.
* The get method accepts an array of keys but doesn't select them in bulk but one at a time.
*
* @todo Orange-Management/phpOMS#122
* Split/Refactor.
* Child extends parent. Parent creates GetMapper, CreateMapper etc.
* Example:
* ```User::get(...)```
* The get() function (defined in an abstract class) creates internally an instance of GetMapper.
* The GetMapper receives all information such as primaryField, columns etc internally from the get().
* This transfer of knowledge to the GetMapper could be done in the abstract class as a setup() function.
* Now all mappers are split. The overhead is one additional function call and the setup() function.
* Alternatively, think about using traits in the beginning.
*
* @todo Orange-Management/phpOMS#162
* Relations by other than primary key
* Currently relations are always defined by the primary key. It would be very helpful to also define relations by other values.
*
* @todo Orange-Management/phpOMS#189
* Allow model creation with ids
* The datamapper checks if the model has an non-empty id before it creates the mode.
* Some models however can have custom primary keys.
* In this case this check should not be done and therefore a $force flag got implemented in order to force the creation of the mode.
* This should be changed by checking if the primary key is autoincrement or not.
* If it isn't autoincrement the model should be created without an additional flag.
* The problem that arises is that now you need to check if the model is already in the database.
* This could be done based on the database response (error).
*
* @todo Orange-Management/phpOMS#212
* Replace nested models which are represented as scalar/id with NullModel
* Currently there is a default limit on dependency nesting when you request a model from the database.
* This means a model may have a model as member and that model in return also has some model as member and so on.
* In order to prevent very deep nesting either the default nesting level is used to limit the amount of nesting or the user can specify a nesting depth.
* Once the lowest nesting level is reached the mapper only stores the id in the member variable and NOT the model.
* As a result the member variable can be of type null, int (= primary key of the model), or the model type.
* This results in many special cases which a coder may has to consider.
* It might make sense to only store null and the model in the member variable.
* In order to still restrict the nesting the mapper could create a null model and only populate the id.
* This could reduce the complexity for the user and simplify the use cases.
* Additionally, it would now be possible to type hint the return value of many getter functions ?NullModelName.
* If this gets implemented we also need to adjust some setter functions.
* Many setter functions allow to only specify a id of the model.
* Either this needs to be prevented and a Null model needs to be provided (all null models must have a __construct(int $id = 0) function which allows to pass the id) or the setter function needs to create the null model based on the id.
* Implementing the above mentioned things will take some time but could improve the simplicity and overall code quality by a lot (at least from my personal opinion).
*
* @todo Orange-Management/phpOMS#213 & Orange-Management/phpOMS#224
* Implement composite models
* All references such as ownsOne, hasMany etc. are based on the mappers for these objects. It should be possible to define single columns only.
* One example where this could be useful is the Address/Localization model.
* In here the country is stored by ID but you probably don't want to load an entire object and only the country name from the country table.
*
* @todo Orange-Management/phpOMS#214
* Allow to define the model class
* Currently the DataMapper uses the mapper name to find the correct model class.
* This can remain but there should be a member variable or const which allows to define the model::class manually in case the model is different.
* One example could be the Address/Location model in the Address module and phpOMS Localization directory.
*
* @todo Orange-Management/Modules#99
* Use binds
* Currently databinds are not used. Currently injections are possible.
*
* @todo Orange-Management/Modules#179
* Replace int models with NullModels
* In many cases int is allowed to represent another model if not the whole model is supposed to be loaded.
* This means we have to check for null, int and model type.
* Instead of using int the NullModel should be used which has a constructor that allows to define the int.
* As a result the datamapper has to be rewritten for the select and insert/update.
* The select needs to set the null model as value and the insert/update needs to extract the id from the null and ignore all other empty values from the null model which obviously are the default values.
*/
class DataMapperAbstract implements DataMapperInterface
{
@ -488,9 +587,7 @@ class DataMapperAbstract implements DataMapperInterface
try {
self::$db->con->prepare($query->toSql())->execute();
} catch (Throwable $t) {
// @todo: remove after debugging
// @fix: really remove it
// @critical: after we found the bug we MUST remove it!
// only for debugging
//var_dump($t->getMessage());
//var_dump($query->toSql());
return -1;
@ -710,16 +807,9 @@ class DataMapperAbstract implements DataMapperInterface
}
// Setting relation value (id) for relation (since the relation is not stored in an extra relation table)
/**
* @todo: this if comparison is correct, trust me. however,
* manybe it makes more sense to simply check if 'src' isset(static::$hasMany[$propertyName]['src'])
* source shouldn't be set if the relation is stored in the object itself
*/
/** @var string $table */
/** @var array $columns */
if (static::$hasMany[$propertyName]['table'] === static::$hasMany[$propertyName]['mapper']::$table
&& isset($mapper::$columns[static::$hasMany[$propertyName]['dst']])
) {
if (!isset(static::$hasMany[$propertyName]['src'])) {
$relProperty = $relReflectionClass->getProperty($mapper::$columns[static::$hasMany[$propertyName]['dst']]['internal']);
if (!$isPublic) {
@ -927,12 +1017,8 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function createRelationTable(string $propertyName, array $objsIds, $objId) : void
{
/** @todo: see hasMany implementation, checking isset(src) might be enough. although second condition MUST remain. */
/** @var string $table */
if (!empty($objsIds)
&& static::$hasMany[$propertyName]['table'] !== static::$table
&& static::$hasMany[$propertyName]['table'] !== static::$hasMany[$propertyName]['mapper']::$table
) {
if (!empty($objsIds) && isset(static::$hasMany[$propertyName]['src'])) {
$relQuery = new Builder(self::$db);
$relQuery->prefix(self::$db->getPrefix())
->into(static::$hasMany[$propertyName]['table'])
@ -1853,7 +1939,10 @@ class DataMapperAbstract implements DataMapperInterface
return $objId;
}
// @todo: implement array delete
/**
* @todo Orange-Management/phpOMS#221
* Create the delete functionality for arrays (deleteArray, deleteArrayModel).
*/
/**
* Populate data.
@ -1947,7 +2036,6 @@ class DataMapperAbstract implements DataMapperInterface
*/
public static function populateManyToMany(array $result, &$obj, int $depth = 3) : void
{
// todo: maybe pass reflectionClass as optional parameter for performance increase
$refClass = new \ReflectionClass($obj);
foreach ($result as $member => $values) {
@ -2002,8 +2090,6 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return void
*
* @todo accept reflection class as parameter
*
* @since 1.0.0
*/
public static function populateOwnsOne(&$obj, int $depth = 3) : void
@ -2011,30 +2097,27 @@ class DataMapperAbstract implements DataMapperInterface
$refClass = new \ReflectionClass($obj);
foreach (static::$ownsOne as $member => $one) {
// todo: is that if necessary? performance is suffering for sure!
if ($refClass->hasProperty($member)) {
$refProp = $refClass->getProperty($member);
$refProp = $refClass->getProperty($member);
if (!($accessible = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
if (!($accessible = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
/** @var string $mapper */
$mapper = static::$ownsOne[$member]['mapper'];
$id = $refProp->getValue($obj);
/** @var string $mapper */
$mapper = static::$ownsOne[$member]['mapper'];
$id = $refProp->getValue($obj);
if (self::isNullObject($id)) {
continue;
}
if (self::isNullObject($id)) {
continue;
}
$id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$refProp->setValue($obj, $value);
$refProp->setValue($obj, $value);
if (!$accessible) {
$refProp->setAccessible(false);
}
if (!$accessible) {
$refProp->setAccessible(false);
}
}
}
@ -2043,7 +2126,6 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return void
*
* @todo accept reflection class as parameter
* @todo do this in the getRaw() part as a join. check if has conditionals and then join the data an then everything can be done in the getModel function.
*
* @since 1.0.0
@ -2078,8 +2160,6 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return void
*
* @todo accept reflection class as parameter
*
* @since 1.0.0
*/
public static function populateOwnsOneArray(array &$obj, int $depth = 3) : void
@ -2102,8 +2182,6 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return void
*
* @todo accept reflection class as parameter
*
* @since 1.0.0
*/
public static function populateBelongsTo(&$obj, int $depth = 3) : void
@ -2111,30 +2189,27 @@ class DataMapperAbstract implements DataMapperInterface
$refClass = new \ReflectionClass($obj);
foreach (static::$belongsTo as $member => $one) {
// todo: is that if necessary? performance is suffering for sure!
if ($refClass->hasProperty($member)) {
$refProp = $refClass->getProperty($member);
$refProp = $refClass->getProperty($member);
if (!($accessible = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
if (!($accessible = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
/** @var string $mapper */
$mapper = static::$belongsTo[$member]['mapper'];
$id = $refProp->getValue($obj);
/** @var string $mapper */
$mapper = static::$belongsTo[$member]['mapper'];
$id = $refProp->getValue($obj);
if (self::isNullObject($id)) {
continue;
}
if (self::isNullObject($id)) {
continue;
}
$id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$refProp->setValue($obj, $value);
$refProp->setValue($obj, $value);
if (!$accessible) {
$refProp->setAccessible(false);
}
if (!$accessible) {
$refProp->setAccessible(false);
}
}
}
@ -2147,8 +2222,6 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return void
*
* @todo accept reflection class as parameter
*
* @since 1.0.0
*/
public static function populateBelongsToArray(array &$obj, int $depth = 3) : void
@ -2180,7 +2253,7 @@ class DataMapperAbstract implements DataMapperInterface
$refClass = new \ReflectionClass($obj);
foreach ($result as $column => $value) {
if (!isset($columns[$column]['internal']) /* && $refClass->hasProperty($columns[$column]['internal']) */) {
if (!isset($columns[$column]['internal'])) {
continue;
}
@ -2293,7 +2366,10 @@ class DataMapperAbstract implements DataMapperInterface
*
* @return mixed
*
* @todo: implement language
* @todo Orange-Management/phpOMS#161
* Reconsider get*() parameter order
* Check if the parameter order of all of the get functions makes sense or if another order would be better.
* Especially the fill parameter probably should be swapped with the depth filter.
*
* @since 1.0.0
*/

View File

@ -24,6 +24,16 @@ use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#33
* Implement missing grammar & builder functions
* Missing elements are e.g. sum, merge etc.
*
* @todo Orange-Management/phpOMS#194
* Automatically set prefix during construction
* When constructing the QueryBuilder or SchemaBuilder the connection is passed.
* The connection holds information about the table prefix, yet I force developers to pass a prefix after the builder initialization.
* This should be done automatically!
*/
class Builder extends BuilderAbstract
{
@ -70,10 +80,10 @@ class Builder extends BuilderAbstract
/**
* Into.
*
* @var \Closure|string
* @var string
* @since 1.0.0
*/
public $into = null;
public string $into = '';
/**
* Into columns.
@ -267,8 +277,6 @@ class Builder extends BuilderAbstract
*
* @return Builder
*
* @todo Closure is not working this way, needs to be evaluated befor assigning
*
* @since 1.0.0
*/
public function select(...$columns) : self
@ -276,7 +284,7 @@ class Builder extends BuilderAbstract
$this->type = QueryType::SELECT;
foreach ($columns as $key => $column) {
if (\is_string($column) || $column instanceof self || $column instanceof \Closure) {
if (\is_string($column) || $column instanceof self) {
$this->selects[] = $column;
} else {
throw new \InvalidArgumentException();
@ -311,8 +319,6 @@ class Builder extends BuilderAbstract
*
* @return Builder
*
* @todo Closure is not working this way, needs to be evaluated befor assigning
*
* @since 1.0.0
*/
public function random(...$columns) : self
@ -338,7 +344,7 @@ class Builder extends BuilderAbstract
{
if (\is_array($binds)) {
$this->binds += $binds;
} elseif (\is_string($binds) || $binds instanceof \Closure) {
} elseif (\is_string($binds)) {
$this->binds[] = $binds;
} else {
throw new \InvalidArgumentException();
@ -451,7 +457,7 @@ class Builder extends BuilderAbstract
public function from(...$tables) : self
{
foreach ($tables as $key => $table) {
if (\is_string($table) || $table instanceof self || $table instanceof \Closure) {
if (\is_string($table) || $table instanceof self) {
$this->from[] = $table;
} else {
throw new \InvalidArgumentException();
@ -481,10 +487,10 @@ class Builder extends BuilderAbstract
/**
* Where.
*
* @param array|\Closure|string|Where $columns Columns
* @param array|string $operator Operator
* @param mixed $values Values
* @param array|string $boolean Boolean condition
* @param array|string|Where $columns Columns
* @param array|string $operator Operator
* @param mixed $values Values
* @param array|string $boolean Boolean condition
*
* @return Builder
*
@ -540,9 +546,9 @@ class Builder extends BuilderAbstract
/**
* Where and sub condition.
*
* @param array|\Closure|string|Where $where Where sub condition
* @param mixed $operator Operator
* @param mixed $values Values
* @param array|string|Where $where Where sub condition
* @param mixed $operator Operator
* @param mixed $values Values
*
* @return Builder
*
@ -556,9 +562,9 @@ class Builder extends BuilderAbstract
/**
* Where or sub condition.
*
* @param array|\Closure|string|Where $where Where sub condition
* @param mixed $operator Operator
* @param mixed $values Values
* @param array|string|Where $where Where sub condition
* @param mixed $operator Operator
* @param mixed $values Values
*
* @return Builder
*
@ -572,9 +578,9 @@ class Builder extends BuilderAbstract
/**
* Where in.
*
* @param array|\Closure|string|Where $column Column
* @param mixed $values Values
* @param string $boolean Boolean condition
* @param array|string|Where $column Column
* @param mixed $values Values
* @param string $boolean Boolean condition
*
* @return Builder
*
@ -590,8 +596,8 @@ class Builder extends BuilderAbstract
/**
* Where null.
*
* @param array|\Closure|string|Where $column Column
* @param string $boolean Boolean condition
* @param array|string|Where $column Column
* @param string $boolean Boolean condition
*
* @return Builder
*
@ -607,8 +613,8 @@ class Builder extends BuilderAbstract
/**
* Where not null.
*
* @param array|\Closure|string|Where $column Column
* @param string $boolean Boolean condition
* @param array|string|Where $column Column
* @param string $boolean Boolean condition
*
* @return Builder
*
@ -624,7 +630,7 @@ class Builder extends BuilderAbstract
/**
* Group by.
*
* @param array|\Closure|string ...$columns Grouping result
* @param array|string ...$columns Grouping result
*
* @return Builder
*
@ -633,7 +639,7 @@ class Builder extends BuilderAbstract
public function groupBy(...$columns) : self
{
foreach ($columns as $key => $column) {
if (\is_string($column) || $column instanceof self || $column instanceof \Closure) {
if (\is_string($column) || $column instanceof self) {
$this->groups[] = $column;
} else {
throw new \InvalidArgumentException();
@ -646,13 +652,13 @@ class Builder extends BuilderAbstract
/**
* Order by newest.
*
* @param \Closure|string $column Column
* @param string $column Column
*
* @return Builder
*
* @since 1.0.0
*/
public function newest($column) : self
public function newest(string $column) : self
{
$this->orderBy($column, 'DESC');
@ -662,13 +668,13 @@ class Builder extends BuilderAbstract
/**
* Order by oldest.
*
* @param \Closure|string $column Column
* @param string $column Column
*
* @return Builder
*
* @since 1.0.0
*/
public function oldest($column) : self
public function oldest(string $column) : self
{
$this->orderBy($column, 'ASC');
@ -678,8 +684,8 @@ class Builder extends BuilderAbstract
/**
* Order by oldest.
*
* @param array|\Closure|string $columns Columns
* @param string|string[] $order Orders
* @param array|string $columns Columns
* @param string|string[] $order Orders
*
* @return Builder
*
@ -687,7 +693,7 @@ class Builder extends BuilderAbstract
*/
public function orderBy($columns, $order = 'DESC') : self
{
if (\is_string($columns) || $columns instanceof \Closure) {
if (\is_string($columns)) {
if (!\is_string($order)) {
throw new \InvalidArgumentException();
}
@ -893,13 +899,13 @@ class Builder extends BuilderAbstract
/**
* Table to insert into.
*
* @param \Closure|string $table Table
* @param string $table Table
*
* @return Builder
*
* @since 1.0.0
*/
public function into($table) : self
public function into(string $table) : self
{
$this->into = $table;
@ -1011,7 +1017,7 @@ class Builder extends BuilderAbstract
$this->type = QueryType::UPDATE;
foreach ($tables as $key => $table) {
if (\is_string($table) || $table instanceof self || $table instanceof \Closure) {
if (\is_string($table) || $table instanceof self) {
$this->updates[] = $table;
} else {
throw new \InvalidArgumentException();
@ -1074,7 +1080,7 @@ class Builder extends BuilderAbstract
*/
public function join($table, string $type = JoinType::JOIN, string $alias = null) : self
{
if (!\is_string($table)&& !($table instanceof self) && !($table instanceof \Closure)) {
if (!\is_string($table)&& !($table instanceof self)) {
throw new \InvalidArgumentException();
}
@ -1292,7 +1298,8 @@ class Builder extends BuilderAbstract
throw new \InvalidArgumentException('Unknown operator.');
}
// @todo: this is bad! ons needs to have the same key as the join for the grammar to work. since alias are possible this is nec3essary.
// ons needs to have the same key as the join for the grammar to work
// since alias are possible this is necessary
$this->ons[\array_keys($this->joins)[$joinCount]][] = [
'column' => $column,
'operator' => $operator[$i],
@ -1407,8 +1414,6 @@ class Builder extends BuilderAbstract
return $column;
} elseif ($column instanceof Column) {
return $column->getColumn();
} elseif ($column instanceof \Closure) {
return $column();
} elseif ($column instanceof \Serializable) {
return $column->serialize();
}

View File

@ -28,6 +28,10 @@ use phpOMS\DataStorage\Database\Query\Where;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#33
* Implement missing grammar & builder functions
* Missing elements are e.g. sum, merge etc.
*/
class Grammar extends GrammarAbstract
{

View File

@ -24,6 +24,10 @@ use phpOMS\DataStorage\Database\Query\Builder as QueryBuilder;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#32
* Implement schema grammar
* Basic create/drop schema grammar created. Next step is to be able to update existing schema and read existing schema.
*/
class Builder extends QueryBuilder
{

View File

@ -25,6 +25,10 @@ use phpOMS\DataStorage\Database\Schema\QueryType;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#32
* Implement schema grammar
* Basic create/drop schema grammar created. Next step is to be able to update existing schema and read existing schema.
*/
class Grammar extends QueryGrammar
{

View File

@ -24,6 +24,10 @@ use phpOMS\DataStorage\Database\Query\Builder;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#32
* Implement schema grammar
* Basic create/drop schema grammar created. Next step is to be able to update existing schema and read existing schema.
*/
class MysqlGrammar extends Grammar
{

View File

@ -136,8 +136,7 @@ final class CubicSplineInterpolation implements InterpolationInterface
$this->solveC->setV($n - 1, 3.0 * $this->solveA->getV($n - 2) * $h ** 2 + 2.0 * $this->solveB->get($n - 2) * $h + $this->solveC->getV($n - 2));
/**
* @todo: consider linear extrapolation at start and end point
*
* linear extrapolation at start and end point
* $this->solveB->setV($n - 1, 0.0)
*/
}
@ -164,8 +163,7 @@ final class CubicSplineInterpolation implements InterpolationInterface
if ($x < $this->points[0]['x']) {
return ($this->solveB->get(0) * $h + $this->solveC->getV(0)) * $h + $this->points[0]['y'];
/**
* @todo: consider linear extrapolation at start and end point
*
* linear extrapolation at start and end point
* ($this->solveC->getV(0)) * $h + $this->points[0]['y'];
*/
} elseif ($x > $this->points[$n - 1]['x']) {

View File

@ -272,6 +272,10 @@ final class Average
\sort($values);
if ($offset > 0) {
/**
* @todo Orange-Management/phpOMS#175
* Create unit test.
*/
$values = \array_slice($values, $offset, -$offset);
}
@ -339,6 +343,10 @@ final class Average
\sort($angles);
if ($offset > 0) {
/**
* @todo Orange-Management/phpOMS#176
* Create unit test.
*/
$angles = \array_slice($angles, $offset, -$offset);
}

View File

@ -218,6 +218,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#167
* Create unit test.
*
* @since 1.0.0
*/
public static function getAkaikeInformationCriterion(float $sse, int $observations, int $predictors) : float
@ -252,6 +255,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#168
* Create unit test.
*
* @since 1.0.0
*/
public static function getSchwarzBayesianInformationCriterion(float $sse, int $observations, int $predictors) : float
@ -267,6 +273,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#169
* Create unit test.
*
* @since 1.0.0
*/
public static function getMeanAbsolutePercentageError(array $observed, array $forecasted) : float
@ -282,6 +291,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#170
* Create unit test.
*
* @since 1.0.0
*/
public static function getSymmetricMeanAbsolutePercentageError(array $observed, array $forecasted) : float
@ -303,6 +315,9 @@ final class Error
*
* @return array
*
* @todo Orange-Management/phpOMS#172
* Create unit test.
*
* @since 1.0.0
*/
public static function getCrossSectionalScaledErrorArray(array $errors, array $observed) : array
@ -325,6 +340,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#171
* Create unit test.
*
* @since 1.0.0
*/
public static function getCrossSectionalScaledError(float $error, array $observed) : float
@ -360,6 +378,9 @@ final class Error
*
* @return float
*
* @todo Orange-Management/phpOMS#173
* Create unit test.
*
* @since 1.0.0
*/
public static function getMeanSquaredScaledError(array $scaledErrors) : float

View File

@ -35,8 +35,6 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getPmf(int $K, int $N, int $k, int $n) : float
@ -53,8 +51,6 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getMean(int $K, int $N, int $n) : float
@ -71,8 +67,6 @@ final class HypergeometricDistribution
*
* @return int
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getMode(int $K, int $N, int $n) : int
@ -89,8 +83,6 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getVariance(int $K, int $N, int $n) : float
@ -107,13 +99,11 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getStandardDeviation(int $K, int $N, int $n) : float
{
return \sqrt(self::getVariance($K, $N, $n));
return \sqrt($n * $K / $N * ($N - $K) / $N * ($N - $n) / ($N - 1));
}
/**
@ -125,8 +115,6 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getSkewness(int $K, int $N, int $n) : float
@ -144,8 +132,6 @@ final class HypergeometricDistribution
*
* @return float
*
* @todo: this can be heavily optimized
*
* @since 1.0.0
*/
public static function getExKurtosis(int $K, int $N, int $n) : float

View File

@ -115,7 +115,7 @@ final class Request extends RequestAbstract
if (!isset($this->uri)) {
$this->initCurrentRequest();
$this->lock();
$this->cleanupGlobals();
self::cleanupGlobals();
$this->setupUriBuilder();
}
@ -247,11 +247,9 @@ final class Request extends RequestAbstract
*
* @return void
*
* @todo: consider making this function static.
*
* @since 1.0.0
*/
private function cleanupGlobals() : void
public static function cleanupGlobals() : void
{
unset($_FILES);
unset($_GET);
@ -463,11 +461,9 @@ final class Request extends RequestAbstract
*
* @throws \OutOfRangeException This exception is thrown if the port is out of range
*
* @todo: consider making this static
*
* @since 1.0.0
*/
public function isHttps(int $port = 443) : bool
public static function isHttps(int $port = 443) : bool
{
if ($port < 1 || $port > 65535) {
throw new \OutOfRangeException('Value "' . $port . '" is out of range.');

View File

@ -166,41 +166,32 @@ final class Response extends ResponseAbstract implements RenderableInterface
/**
* {@inheritdoc}
* @todo: this whole workflow with json got improved a little bit but this part looks bad. do i really need so much code or could i simplify it
*/
public function toArray() : array
{
$result = [];
try {
foreach ($this->response as $key => $response) {
if ($response instanceof View) {
$result[] = $response->toArray();
} elseif (\is_array($response)) {
$result[] = $response;
} elseif (\is_scalar($response)) {
$result[] = $response;
} elseif ($response instanceof \JsonSerializable) {
$result[] = $response->jsonSerialize();
} elseif ($response === null) {
continue;
} else {
throw new \Exception('Wrong response type');
}
foreach ($this->response as $response) {
if ($response instanceof View) {
$result[] = $response->toArray();
} elseif (\is_array($response) || \is_scalar($response)) {
$result[] = $response;
} elseif ($response instanceof \JsonSerializable) {
$result[] = $response->jsonSerialize();
} elseif ($response === null) {
continue;
} else {
FileLogger::getInstance('', false)
->error(
FileLogger::MSG_FULL, [
'message' => 'Unknown type.',
'line' => __LINE__,
'file' => self::class,
]
);
}
} catch (\Exception $e) {
FileLogger::getInstance('', false)
->error(
FileLogger::MSG_FULL, [
'message' => $e->getMessage(),
'line' => __LINE__,
'file' => self::class,
]
);
$result = [];
} finally {
return $result;
}
return $result;
}
}

View File

@ -21,6 +21,9 @@ namespace phpOMS\Message\Mail;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#34
* Implement!!!
*/
class EmailAbstract
{

View File

@ -148,41 +148,32 @@ final class Response extends ResponseAbstract implements RenderableInterface
/**
* {@inheritdoc}
* @todo: this whole workflow with json got improved a little bit but this part looks bad. do i really need so much code or could i simplify it
*/
public function toArray() : array
{
$result = [];
try {
foreach ($this->response as $key => $response) {
if ($response instanceof View) {
$result[] = $response->toArray();
} elseif (\is_array($response)) {
$result[] = $response;
} elseif (\is_scalar($response)) {
$result[] = $response;
} elseif ($response instanceof \JsonSerializable) {
$result[] = $response->jsonSerialize();
} elseif ($response === null) {
continue;
} else {
throw new \Exception('Wrong response type');
}
foreach ($this->response as $response) {
if ($response instanceof View) {
$result[] = $response->toArray();
} elseif (\is_array($response) || \is_scalar($response)) {
$result[] = $response;
} elseif ($response instanceof \JsonSerializable) {
$result[] = $response->jsonSerialize();
} elseif ($response === null) {
continue;
} else {
FileLogger::getInstance('', false)
->error(
FileLogger::MSG_FULL, [
'message' => 'Unknown type.',
'line' => __LINE__,
'file' => self::class,
]
);
}
} catch (\Exception $e) {
FileLogger::getInstance('', false)
->error(
FileLogger::MSG_FULL, [
'message' => $e->getMessage(),
'line' => __LINE__,
'file' => self::class,
]
);
$result = [];
} finally {
return $result;
}
return $result;
}
}

View File

@ -27,8 +27,8 @@ use phpOMS\System\MimeType;
* @link https://orange-management.org
* @since 1.0.0
*
* @todo: maybe move to Modules because this is very project specific and not general enough for a framework
* @todo: maybe move all of the Module\classes parts to the Modules\?
* @todo Orange-Management/Modules#113
* Don't use name but id for identification
*/
abstract class ModuleAbstract
{

View File

@ -31,6 +31,9 @@ use phpOMS\System\File\PathException;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/Modules#113
* Don't use name but id for identification
*/
final class ModuleManager
{

View File

@ -21,6 +21,26 @@ namespace phpOMS\Router;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#191
* Implement routing parameters
* Most routing implementations have parameters in their route e.g.
* 'route' => '/your/url/{@id}/something'
* This is very easy to read but slows down performance.
* 'route' => [
* 'match' => '/your/url/.*?/something',
* 'parameters'=> [
* 'id' => ['type' => 'path', 'index' => 2]
* ]
* ]
* The parameters should then be passed to the method in the $data = [] variable.
*
* @todo Orange-Management/phpOMS#192
* Implement form/api data validation
* Similar to permission validation it could be possible to add data constraints which are expected for certain routes which then could be checked during routing and dispatching.
* For example it would be possible to define required data fields, their type, their pattern etc.
* This would make the routing definitions much bigger but also dramatically reduce the work which needs to be done in the controllers.
* It could even be written in a way which hardly effects performance.
*/
final class WebRouter implements RouterInterface
{

View File

@ -21,8 +21,6 @@ namespace phpOMS\Stdlib\Graph;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition
*/
class BinaryTree extends Tree
{

View File

@ -21,8 +21,6 @@ namespace phpOMS\Stdlib\Graph;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition
*/
class Node
{

View File

@ -21,6 +21,11 @@ namespace phpOMS\Utils;
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#154
* Create excel operations on arrays
* In many cases there are values stored inside of arrays which need simple math operators performed on them.
* Instead of writing the expression it should be possible to do this in good old excel fasion.
*/
final class ArrayUtils
{
@ -386,6 +391,9 @@ final class ArrayUtils
*
* @return array<float>
*
* @todo Orange-Management/phpOMS#223
* In the ArrayUtils class the power* functions should be combined once union types become available.
*
* @since 1.0.0
*/
public static function powerFloat(array $values, float $exp = 2.0) : array
@ -407,6 +415,9 @@ final class ArrayUtils
*
* @return array<float|int>
*
* @todo Orange-Management/phpOMS#223
* In the ArrayUtils class the power* functions should be combined once union types become available.
*
* @since 1.0.0
*/
public static function powerInt(array $values, int $exp = 2) : array

View File

@ -210,8 +210,6 @@ class Markdown
/**
* Some definition data for elements
*
* @todo: figure out what it is for
*
* @var string[]
* @since 1.0.0
*/

View File

@ -26,6 +26,10 @@ use phpOMS\Contract\RenderableInterface;
* @link https://orange-management.org
* @since 1.0.0
*
* @todo Orange-Management/phpOMS#119
* Create jaro winkler distance
* https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance
*
* @SuppressWarnings(PHPMD.CamelCaseMethodName)
*/
final class StringUtils

View File

@ -202,7 +202,10 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals($this->model->datetime->format('Y-m-d'), $modelR->datetime->format('Y-m-d'));
self::assertNull($modelR->datetime_null);
// todo implement these
/**
* @todo Orange-Management/phpOMS#227
* Serializable and JsonSerializable data can be inserted and updated in the database but it's not possible to correctly populate a model with the data in its original format.
*/
//self::assertEquals('123', $modelR->serializable);
//self::assertEquals($this->model->json, $modelR->json);
//self::assertEquals([1, 2, 3], $modelR->jsonSerializable);
@ -281,7 +284,10 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals($modelR->datetime->format('Y-m-d'), $modelR2->datetime->format('Y-m-d'));
self::assertNull($modelR2->datetime_null);
// todo test update relations
/**
* @todo Orange-Management/phpOMS#226
* Test the update of a model with relations (update relations).
*/
}
/**
@ -313,7 +319,10 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals($modelR['datetime']->format('Y-m-d'), $modelR2['datetime']->format('Y-m-d'));
self::assertNull($modelR2['datetime_null']);
// todo test update relations
/**
* @todo Orange-Management/phpOMS#226
* Test the update of a model with relations (update relations).
*/
}
/**
@ -329,6 +338,9 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertInstanceOf('phpOMS\tests\DataStorage\Database\TestModel\NullBaseModel', $modelR);
// todo test if relations also deleted
/**
* @todo Orange-Management/phpOMS#225
* Test the deletion of a model with relations (deleting relations).
*/
}
}

View File

@ -59,15 +59,6 @@ class BuilderTest extends \PHPUnit\Framework\TestCase
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'' . $datetime->format('Y-m-d H:i:s') . '\';';
self::assertEquals($sql, $query->select('a.test', 'b.test')->from('a', 'b')->where('a.test', '=', $datetime)->toSql());
$query = new Builder($this->con);
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'abc\' AND `b`.`test` = 2;';
$systemIdentifier = '`';
self::assertEquals($sql, $query->select('a.test', function () {
return '`b`.`test`';
})->from('a', function () use ($systemIdentifier) {
return $systemIdentifier . 'b' . $systemIdentifier;
})->where(['a.test', 'b.test'], ['=', '='], ['abc', 2], ['and', 'and'])->toSql());
$query = new Builder($this->con);
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'abc\' ORDER BY `a`.`test` ASC, `b`.`test` DESC;';
self::assertEquals($sql,

View File

@ -269,7 +269,12 @@ class MatrixTest extends \PHPUnit\Framework\TestCase
]);
self::markTestIncomplete();
// todo: result column 0 and 1 are swapped. why? still correct?
/**
* @todo Orange-Management/phpOMS#179
* Create unit test for inverse.
* It seems like some columns are ordered in a different way
*/
/*self::assertEquals([
[-0.9, -0.5, 2.2],
[0.7, 0.5, -1.6],

View File

@ -45,7 +45,7 @@ class RequestTest extends \PHPUnit\Framework\TestCase
self::assertEquals(BrowserType::UNKNOWN, $request->getBrowser());
self::assertEquals(OSType::UNKNOWN, $request->getOS());
self::assertEquals('127.0.0.1', $request->getOrigin());
self::assertFalse($request->isHttps());
self::assertFalse(Request::isHttps());
self::assertEquals([], $request->getHash());
self::assertEmpty($request->getBody());
self::assertEmpty($request->getFiles());

View File

@ -215,6 +215,10 @@ class ArrayUtilsTest extends \PHPUnit\Framework\TestCase
/**
* @testdox All array values in an array can be potentiated by an integer
* @covers phpOMS\Utils\ArrayUtils
*
* @todo Orange-Management/phpOMS#223
* In the ArrayUtils class the power* functions should be combined once union types become available.
*
* @group framework
*/
public function testPowerInt() : void
@ -227,7 +231,9 @@ class ArrayUtilsTest extends \PHPUnit\Framework\TestCase
* @testdox All array values in an array can be potentiated by a float
* @covers phpOMS\Utils\ArrayUtils
*
* @todo combine with int as soon as union types exist
* @todo Orange-Management/phpOMS#223
* In the ArrayUtils class the power* functions should be combined once union types become available.
*
* @group framework
*/
public function testPowerFloat() : void

View File

@ -20,7 +20,6 @@ use phpOMS\Utils\Git\Repository;
* @testdox phpOMS\tests\Utils\Git\RepositoryTest: Git repository
*
* @internal
* @todo create tests for other functions
*/
class RepositoryTest extends \PHPUnit\Framework\TestCase
{

View File

@ -38,7 +38,9 @@ class ScheduleTest extends \PHPUnit\Framework\TestCase
/**
* @testdox A task can be created from an array and rendered
* @covers phpOMS\Utils\TaskSchedule\Schedule
*
* @todo the interval has to be implemented!
*
* @group framework
*/
public function testCreateJobWithData() : void

View File

@ -33,10 +33,5 @@ class SchedulerFactoryTest extends \PHPUnit\Framework\TestCase
public function testCreate() : void
{
self::assertTrue((SchedulerFactory::create() instanceof Cron) || (SchedulerFactory::create() instanceof TaskScheduler));
// todo: make full test here by defining schtask or crontab path
// todo: create task
// todo: get task
// todo: remove task
}
}