├── .editorconfig ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── README.md ├── changelog.md ├── codeception.dist.yml ├── composer.json ├── src ├── Alias.php ├── Model.php ├── ModelCollection.php ├── ModelCollectionInterface.php ├── ModelInterface.php ├── Provider.php ├── ProviderFactory.php ├── ProviderInterface.php ├── Query.php ├── QueryBuilder │ └── Fuel.php ├── QueryBuilderInterface.php ├── QueryInterface.php └── Relation │ ├── AbstractRelation.php │ └── HasMany.php └── tests ├── _bootstrap.php ├── _data └── dump.sql ├── _helpers ├── CodeHelper.php ├── TestHelper.php └── WebHelper.php ├── _log └── .gitkeep ├── unit.suite.yml └── unit ├── AliasTest.php ├── CodeGuy.php ├── ModelCollectionTest.php ├── ModelTest.php ├── ProviderFactoryTest.php ├── ProviderTest.php ├── QueryTest.php ├── RelationHasManyTest.php ├── _bootstrap.php └── stubs ├── Provider └── PostProvider.php ├── ProviderStub.php └── Relation └── AbstractRelationStub.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [composer.json] 10 | indent_style = tab 11 | indent_size = 4 12 | 13 | [*.php] 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [*.yml] 18 | indent_style = space 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vendor 3 | coverage 4 | /cache 5 | composer.lock 6 | *~ 7 | *.bak 8 | Thumbs.db 9 | desktop.ini 10 | .buildpath 11 | .project 12 | .settings 13 | nbproject/ 14 | .idea 15 | *.tmproj 16 | *.sublime-project 17 | *.sublime-workspace 18 | /index.php 19 | composer.phar 20 | tests/_log/* 21 | /codeception.yml 22 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - php 3 | tools: 4 | external_code_coverage: 5 | timeout: 600 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | php: 6 | - 5.4 7 | - 5.5 8 | - 5.6 9 | - hhvm 10 | - 7 11 | 12 | matrix: 13 | allow_failures: 14 | - php: 7 15 | 16 | services: 17 | - mysql 18 | 19 | before_script: 20 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "7" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi;' 21 | - composer install 22 | - mysql -e 'create database fuelphp_orm_tests;' 23 | 24 | script: 25 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "7" ]; then vendor/bin/codecept run unit --coverage-xml; fi;' 26 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" == "hhvm" ] || [ "$TRAVIS_PHP_VERSION" == "7" ]; then vendor/bin/codecept run unit; fi;' 27 | 28 | after_script: 29 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "7" ]; then php ocular.phar code-coverage:upload --format=php-clover tests/_log/coverage.xml; fi;' 30 | 31 | notifications: 32 | irc: "irc.freenode.org#fuelphp-status" 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FuelPHP Orm library. 2 | 3 | [![Build Status](https://travis-ci.org/fuelphp/orm.png?branch=master)](https://travis-ci.org/fuelphp/orm) 4 | [![Code Quality](https://scrutinizer-ci.com/g/fuelphp/orm/badges/quality-score.png?s=3a071a3f142f3b15c1c0db144b3b8c62fa5662e8)](https://scrutinizer-ci.com/g/fuelphp/orm/) 5 | [![Code Coverage](https://scrutinizer-ci.com/g/fuelphp/orm/badges/coverage.png?s=7ead6a412939c54825a917a3bde03f55aba940b8)](https://scrutinizer-ci.com/g/fuelphp/orm/) 6 | [![HHVM Status](http://hhvm.h4cc.de/badge/fuelphp/orm.svg)](http://hhvm.h4cc.de/package/fuelphp/orm) 7 | 8 | V2 orm currently consists of three separate parts that work together to provide a database abstraction via objects. 9 | These parts are `Provider`s, `Query`s and `Model`s. The names of these might change depending on their eventual implementation. 10 | 11 | ## Providers 12 | 13 | A `Provider` contains the model's properties, table name and other related information. If you are familiar with the v1 orm 14 | this replaces the static properties that used to define the properties, relations, connection, table name and observers. 15 | The providers should (at the moment at least) be the first point of entry for interacting with 16 | 17 | ## Queries 18 | 19 | `Query` objects provide a way for the developer to perform actions on the database using the abstraction of the ORM. 20 | The idea is that a `Query` object is responsible for talking to whatever database system you are using, be it MySQL, 21 | noSQL or flat text files. 22 | 23 | ## Models 24 | 25 | `Model`, unlike v1, are dummy data container objects. The intent is to make them as light as possible to make dealing 26 | with large data sets more efficient. They may contain an interface that passes through to a `Query` or `Provider` in the 27 | future. 28 | 29 | # Testing 30 | 31 | Just as a note, the database related tests can grab a valid DB instance from the codeguy class, this loads the config 32 | from the main codeception.yml config so you only need to update the DB config in one place to run the tests. 33 | 34 | In the tests classes this can be fetched with `$this->codeGuy->getDbInstance()` 35 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this package wil be docuented in this file. 3 | 4 | ## [Unreleased][unreleased] 5 | 6 | ## [2.0.0] - 2015-01-01 7 | ### Added 8 | - Inital release 9 | 10 | -------------------------------------------------------------------------------- /codeception.dist.yml: -------------------------------------------------------------------------------- 1 | paths: 2 | tests: tests 3 | log: tests/_log 4 | data: tests/_data 5 | helpers: tests/_helpers 6 | settings: 7 | bootstrap: _bootstrap.php 8 | suite_class: \PHPUnit_Framework_TestSuite 9 | colors: false 10 | memory_limit: 1024M 11 | log: true 12 | modules: 13 | config: 14 | Db: 15 | dsn: 'mysql:host=127.0.0.1;dbname=fuelphp_orm_tests' 16 | user: 'root' 17 | password: '' 18 | dump: tests/_data/dump.sql 19 | populate: true 20 | cleanup: true 21 | coverage: 22 | enabled: true 23 | include: 24 | - src/* 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fuelphp/orm", 3 | "type": "library", 4 | "description": "FuelPHP ORM package", 5 | "keywords": ["ORM", "Activerecord", "Datamapper"], 6 | "homepage": "https://github.com/fuelphp/orm", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "FuelPHP Development Team", 11 | "email": "team@fuelphp.com" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.4", 16 | "fuelphp/common": "dev-master" 17 | }, 18 | "require-dev": { 19 | "codeception/codeception": "~2.0.0", 20 | "codeception/mockery-module": "dev-master", 21 | "fuelphp/database": "dev-master" 22 | }, 23 | "autoload": { 24 | "psr-4": { "Fuel\\Orm\\": "src/" } 25 | }, 26 | "suggest": { 27 | "fuelphp/validation": "Allows models to be validated" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Alias.php: -------------------------------------------------------------------------------- 1 | tableAliases)) 52 | { 53 | // The alias does not exist yet so create one 54 | $this->tableAliases[$table] = 't' . $this->tableAliasCounter++; 55 | } 56 | 57 | return $this->tableAliases[$table]; 58 | } 59 | 60 | /** 61 | * Takes an existing table alias and returns a table name if the alias is known. 62 | * 63 | * @param string $alias 64 | * 65 | * @return string 66 | * 67 | * @throws LogicException 68 | * 69 | * @since 2.0 70 | */ 71 | public function reverseTableAlias($alias) 72 | { 73 | $searchResult = array_search($alias, $this->tableAliases); 74 | 75 | if ($searchResult === false) 76 | { 77 | throw new LogicException('ORM-007: ['.$alias.'] is not a known alias'); 78 | } 79 | 80 | return $searchResult; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/Model.php: -------------------------------------------------------------------------------- 1 | setOriginalData($data); 54 | } 55 | 56 | /** 57 | * Sets the original data for this model 58 | * 59 | * @param array|DataContainer $data 60 | * 61 | * @throws \InvalidArgumentException 62 | * 63 | * @since 2.0 64 | */ 65 | protected function setOriginalData($data) 66 | { 67 | if (is_array($data)) 68 | { 69 | $data = new DataContainer($data); 70 | } 71 | 72 | // Make sure the original data can't be changed 73 | $data->setReadOnly(true); 74 | 75 | $this->originalData = $data; 76 | } 77 | 78 | /** 79 | * Sets the isNew status 80 | * 81 | * @param bool $status 82 | * 83 | * @return $this 84 | * 85 | * @throws \InvalidArgumentException 86 | * 87 | * @since 2.0 88 | */ 89 | public function setIsNew($status) 90 | { 91 | if ( ! is_bool($status)) 92 | { 93 | throw new \InvalidArgumentException('ORM-001: The isNew status must be boolean'); 94 | } 95 | 96 | $this->isNew = $status; 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Returns true if this model is new 103 | * 104 | * @return bool 105 | * 106 | * @since 2.0 107 | */ 108 | public function isNew() 109 | { 110 | return $this->isNew; 111 | } 112 | 113 | /** 114 | * Gets the original data assigned to this model 115 | * 116 | * @return DataContainer 117 | * 118 | * @since 2.0 119 | */ 120 | public function getOriginalData() 121 | { 122 | return $this->originalData; 123 | } 124 | 125 | /** 126 | * Sets the Provider that created this model 127 | * 128 | * @param ProviderInterface $provider 129 | * 130 | * @return $this 131 | */ 132 | public function setProvider(ProviderInterface $provider) 133 | { 134 | $this->provider = $provider; 135 | 136 | return $this; 137 | } 138 | 139 | /** 140 | * Gets the Provider for this model 141 | * 142 | * @return ProviderInterface 143 | */ 144 | public function getProvider() 145 | { 146 | return $this->provider; 147 | } 148 | 149 | /** 150 | * Gets the model's data as an array 151 | * 152 | * @return array 153 | * 154 | * @since 2.0 155 | */ 156 | public function toArray() 157 | { 158 | return $this->data; 159 | } 160 | 161 | /** 162 | * {@inheritdoc} 163 | */ 164 | public function get($key = null, $default = null) 165 | { 166 | // Check if the property requested is a relation 167 | if ($this->provider !== null and $this->provider->hasRelation($key)) 168 | { 169 | return $this->loadRelations($key); 170 | } 171 | 172 | // Not a relation so throw the call up to the parent 173 | return parent::get($key, $default); 174 | } 175 | 176 | /** 177 | * @param string $name 178 | * 179 | * @return ModelCollectionInterface|ModelInterface|null 180 | * 181 | * @since 2.0 182 | */ 183 | protected function loadRelations($name) 184 | { 185 | // Does it need loading? 186 | if ( ! isset($this->populatedRelations[$name])) 187 | { 188 | // It does so grab the data 189 | $this->populatedRelations[$name] = $this->provider 190 | ->getRelation($name) 191 | ->getModels($this); 192 | } 193 | 194 | // Return the relation 195 | return Arr::get($this->populatedRelations, $name); 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/ModelCollection.php: -------------------------------------------------------------------------------- 1 | modelClass; 62 | } 63 | 64 | /** 65 | * @param string $modelClass 66 | * 67 | * @since 2.0 68 | * 69 | * @throws InvalidArgumentException 70 | */ 71 | public function setModelClass($modelClass) 72 | { 73 | if ( ! is_string($modelClass)) 74 | { 75 | $actualClass = gettype($modelClass); 76 | 77 | if (is_object($modelClass)) 78 | { 79 | $actualClass = get_class($modelClass); 80 | } 81 | 82 | throw new InvalidArgumentException('ORM-004: The model class name must be a string, [' . $actualClass . '] passed instead.'); 83 | } 84 | 85 | $this->modelClass = $modelClass; 86 | } 87 | 88 | /** 89 | * The given value must be an instance of the $modelClass 90 | * 91 | * @inheritdoc 92 | */ 93 | public function set($key, $value) 94 | { 95 | $targetClass = $this->getModelClass(); 96 | if ( ! is_object($value) or ! $value instanceof $targetClass) 97 | { 98 | $actualClass = gettype($value); 99 | 100 | if (is_object($value)) 101 | { 102 | $actualClass = get_class($value); 103 | } 104 | 105 | throw new InvalidArgumentException('ORM-005: Invalid model instance. Expecting [' . $this->getModelClass() . '] got [' . $actualClass . ']'); 106 | } 107 | 108 | if ($value->getProvider() === null and $this->getProvider() !== null) 109 | { 110 | $value->setProvider($this->getProvider()); 111 | } 112 | 113 | return parent::set($key, $value); 114 | } 115 | 116 | /** 117 | * Sets the parent provider. 118 | * 119 | * @param ProviderInterface $provider 120 | * 121 | * @since 2.0 122 | */ 123 | public function setProvider(ProviderInterface $provider) 124 | { 125 | $this->provider = $provider; 126 | } 127 | 128 | /** 129 | * Gets the provider assigned to this collection. 130 | * 131 | * @return ProviderInterface 132 | * 133 | * @since 2.0 134 | */ 135 | public function getProvider() 136 | { 137 | return $this->provider; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/ModelCollectionInterface.php: -------------------------------------------------------------------------------- 1 | queryBuilder = $queryBuilder; 73 | } 74 | 75 | /** 76 | * Returns a list of properties. 77 | * 78 | * @return array 79 | * 80 | * @since 2.0 81 | */ 82 | public function getProperties() 83 | { 84 | return $this->properties; 85 | } 86 | 87 | /** 88 | * Sets the provider's properties. 89 | * 90 | * @param array $properties 91 | * 92 | * @since 2.0 93 | */ 94 | public function setProperties($properties) 95 | { 96 | $this->properties = $properties; 97 | } 98 | 99 | /** 100 | * Creates a new instance of the Provider's Model 101 | * 102 | * @param array $data Optional default data for the Model to contain 103 | * 104 | * @return ModelInterface 105 | * 106 | * @since 2.0 107 | */ 108 | public function forgeModelInstance($data = []) 109 | { 110 | $class = $this->getModelClass(); 111 | 112 | /** @type ModelInterface $instance */ 113 | $instance = new $class((array) $data); 114 | $instance->setProvider($this); 115 | 116 | return $instance; 117 | } 118 | 119 | /** 120 | * Creates model instances from assorted data 121 | * 122 | * @param array $data 123 | * 124 | * @return ModelCollectionInterface|ModelInterface 125 | * 126 | * @since 2.0 127 | */ 128 | public function hydrate($data) 129 | { 130 | $models = []; 131 | 132 | foreach ($data as $modelData) 133 | { 134 | $models[] = $this->forgeModelInstance($modelData); 135 | } 136 | 137 | if (count($models) == 1) 138 | { 139 | return $models[0]; 140 | } 141 | 142 | // make sure a collection is returned if needed 143 | return $this->forgeModelCollectionInstance($models); 144 | } 145 | 146 | /** 147 | * {@inheritdoc} 148 | */ 149 | public function forgeModelCollectionInstance($models = []) 150 | { 151 | $class = $this->getModelCollectionClass(); 152 | 153 | /** @type ModelCollectionInterface $instance */ 154 | $instance = new $class($models); 155 | 156 | $instance->setModelClass($this->getModelClass()); 157 | $instance->setProvider($this); 158 | 159 | return $instance; 160 | } 161 | 162 | /** 163 | * Gets the class name of the model that this provider will create. 164 | * 165 | * @return string 166 | * 167 | * @throws RuntimeException 168 | * 169 | * @since 2.0 170 | */ 171 | public function getModelClass() 172 | { 173 | if ( ! is_subclass_of($this->modelClass, 'Fuel\Orm\ModelInterface')) 174 | { 175 | throw new RuntimeException('ORM-002: The given model class must implement ModelInterface'); 176 | } 177 | 178 | return $this->modelClass; 179 | } 180 | 181 | /** 182 | * Gets the class name of the model collection that this provider will use 183 | * 184 | * @return string 185 | * 186 | * @since 2.0 187 | */ 188 | public function getModelCollectionClass() 189 | { 190 | return $this->modelCollectionClass; 191 | } 192 | 193 | /** 194 | * Gets a Query object that can be used to interact with this provider's table 195 | * 196 | * @return QueryInterface 197 | * 198 | * @since 2.0 199 | */ 200 | public function getQuery() 201 | { 202 | return new Query($this); 203 | } 204 | 205 | /** 206 | * Gets the name of the table assigned to this Provider. 207 | * 208 | * @return string 209 | * 210 | * @throws RuntimeException If there is no specified table name 211 | * 212 | * @since 2.0 213 | */ 214 | public function getTableName() 215 | { 216 | if ($this->tableName === null) 217 | { 218 | throw new RuntimeException('ORM-003: No table name specified for [' . get_called_class() . ']'); 219 | } 220 | 221 | return $this->tableName; 222 | } 223 | 224 | /** 225 | * Sets the table name that the provider will use. 226 | * 227 | * @param string $name 228 | * 229 | * @since 2.0 230 | */ 231 | public function setTableName($name) 232 | { 233 | $this->tableName = $name; 234 | } 235 | 236 | /** 237 | * Sets the query builder to use to generate queries 238 | * 239 | * @param QueryBuilderInterface $queryBuilder 240 | * 241 | * @return $this 242 | * 243 | * @since 2.0 244 | */ 245 | public function setQueryBuilder(QueryBuilderInterface $queryBuilder) 246 | { 247 | $this->queryBuilder = $queryBuilder; 248 | 249 | return $this; 250 | } 251 | 252 | /** 253 | * Gets the query builder that this provider will use 254 | * 255 | * @return QueryBuilderInterface 256 | * 257 | * @since 2.0 258 | */ 259 | public function getQueryBuilder() 260 | { 261 | return $this->queryBuilder; 262 | } 263 | 264 | /** 265 | * {@inheritdoc} 266 | */ 267 | public function addRelation($name, AbstractRelation $relation) 268 | { 269 | $this->relations[$name] = $relation; 270 | 271 | return $this; 272 | } 273 | 274 | /** 275 | * {@inheritdoc} 276 | */ 277 | public function hasRelation($name) 278 | { 279 | return isset($this->relations[$name]); 280 | } 281 | 282 | /** 283 | * Gets all relations assigned to this provider 284 | * 285 | * @return AbstractRelation[] 286 | * 287 | * @since 2.0 288 | */ 289 | public function getRelations() 290 | { 291 | return $this->relations; 292 | } 293 | 294 | /** 295 | * {@inheritdoc} 296 | */ 297 | public function getRelation($name) 298 | { 299 | if ( ! $this->hasRelation($name)) 300 | { 301 | throw new InvalidArgumentException('ORM-008: Relation ['.$name.'] does not exist in ['.get_called_class().']'); 302 | } 303 | 304 | return $this->relations[$name]; 305 | } 306 | 307 | /** 308 | * {@inheritdoc} 309 | */ 310 | public function getFactory() 311 | { 312 | return $this->factory; 313 | } 314 | 315 | /** 316 | * {@inheritdoc} 317 | */ 318 | public function setFactory(ProviderFactory $factory) 319 | { 320 | $this->factory = $factory; 321 | } 322 | 323 | } 324 | -------------------------------------------------------------------------------- /src/ProviderFactory.php: -------------------------------------------------------------------------------- 1 | '\Fuel\Orm\Relation\HasMany', 42 | ]; 43 | 44 | public function __construct($queryBuilder = null) 45 | { 46 | $this->queryBuilder = $queryBuilder; 47 | } 48 | 49 | /** 50 | * Adds a new provider definition. 51 | * 52 | * @param string $name 53 | * @param array $properties 54 | * @param string $tableName 55 | * @param array $relations 56 | * 57 | * @since 2.0 58 | */ 59 | public function add($name, $properties, $tableName = null, $relations = []) 60 | { 61 | $this->providerConfigs[$name] = [ 62 | 'name' => $name, 63 | 'properties' => $properties, 64 | 'tableName' => $tableName, 65 | 'relations' => $relations, 66 | ]; 67 | } 68 | 69 | /** 70 | * Adds an already constructed provider to the factory. 71 | * 72 | * @param string $name 73 | * @param ProviderInterface $provider 74 | * 75 | * @since 2.0 76 | */ 77 | public function addInstance($name, ProviderInterface $provider) 78 | { 79 | $this->providers[$name] = $provider; 80 | } 81 | 82 | /** 83 | * Returns true if the given provider is known. 84 | * 85 | * @param string $name 86 | * 87 | * @return bool 88 | * 89 | * @since 2.0 90 | */ 91 | public function has($name) 92 | { 93 | return isset($this->providerConfigs[$name]); 94 | } 95 | 96 | /** 97 | * Gets a constructed provider. 98 | * 99 | * @param string $name 100 | * 101 | * @return Provider 102 | * 103 | * @since 2.0 104 | */ 105 | public function get($name) 106 | { 107 | // Return the provider if it has already been constructed 108 | if (isset($this->providers[$name])) 109 | { 110 | return $this->providers[$name]; 111 | } 112 | 113 | $config = $this->providerConfigs[$name]; 114 | $provider = new Provider; 115 | $provider->setFactory($this); 116 | $provider->setProperties($config['properties']); 117 | $provider->setTableName($config['tableName']); 118 | 119 | // Assign any relations we might have. 120 | $this->assignRelationsToProvider($name, $config['relations'], $provider); 121 | 122 | // Assign a query builder if we have one 123 | if ($this->queryBuilder !== null) 124 | { 125 | $provider->setQueryBuilder($this->queryBuilder); 126 | } 127 | 128 | $this->providers[$name] = $provider; 129 | return $provider; 130 | } 131 | 132 | /** 133 | * Populates the given provider with the relations from the relation config given. 134 | * 135 | * @param string $parentProvider 136 | * @param array $relations 137 | * @param ProviderInterface $provider 138 | * 139 | * @since 2.0 140 | */ 141 | protected function assignRelationsToProvider($parentProvider, $relations, ProviderInterface $provider) 142 | { 143 | foreach ($relations as $type => $configs) 144 | { 145 | // Check if we have a valid class 146 | if ( ! isset($this->relationClasses[$type])) 147 | { 148 | continue; 149 | } 150 | $relationClass = $this->relationClasses[$type]; 151 | 152 | // If so assign all the relations for that type 153 | foreach ($configs as $name => $relationConfig) 154 | { 155 | if (!isset($relationConfig['providerFrom'])) 156 | { 157 | $relationConfig['providerFrom'] = $parentProvider; 158 | } 159 | 160 | $relation = new $relationClass($relationConfig); 161 | $provider->addRelation($name, $relation); 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * Removes a provider. 168 | * 169 | * @param string $name 170 | * 171 | * @since 2.0 172 | */ 173 | public function remove($name) 174 | { 175 | unset($this->providerConfigs[$name]); 176 | unset($this->providers[$name]); 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /src/ProviderInterface.php: -------------------------------------------------------------------------------- 1 | setProvider($provider); 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function setProvider(ProviderInterface $provider) 59 | { 60 | $this->provider = $provider; 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * {@inheritdoc} 67 | */ 68 | public function getProvider() 69 | { 70 | return $this->provider; 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | */ 76 | public function insert($model) 77 | { 78 | $this->queryType = static::$QUERY_INSERT; 79 | $this->getProvider() 80 | ->getQueryBuilder() 81 | ->insert($this->provider->getTableName(), $model); 82 | 83 | $this->insertModel = $model; 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * {@inheritdoc} 90 | */ 91 | public function delete($models) 92 | { 93 | $this->queryType = static::$QUERY_DELETE; 94 | $provider = $this->getProvider(); 95 | $builder = $provider->getQueryBuilder(); 96 | 97 | $builder->delete($provider->getTableName()); 98 | 99 | $inIds = []; 100 | 101 | foreach ($models as $model) 102 | { 103 | // TODO: make sure this uses the actual PK 104 | $inIds[] = $model->id; 105 | } 106 | 107 | if (count($inIds) > 1) 108 | { 109 | $builder->where('id', 'IN', $inIds); 110 | } 111 | else 112 | { 113 | $builder->where('id', '=', $inIds); 114 | } 115 | 116 | return $this; 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | public function select() 123 | { 124 | $this->queryType = static::$QUERY_SELECT; 125 | 126 | $provider = $this->getProvider(); 127 | 128 | $this->provider 129 | ->getQueryBuilder() 130 | ->select($provider->getTableName(), $provider->getProperties()); 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * {@inheritdoc} 137 | */ 138 | public function update($model) 139 | { 140 | // TODO: Find out if multiple updates can be done together. 141 | // TODO: Use model diffs to make the queries smaller 142 | 143 | $this->queryType = static::$QUERY_UPDATE; 144 | $this->getProvider() 145 | ->getQueryBuilder() 146 | ->update($this->getProvider()->getTableName(), $model); 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * {@inheritdoc} 153 | */ 154 | public function where($property, $operator, $value = null) 155 | { 156 | if ($value === null) 157 | { 158 | $value = $operator; 159 | $operator = '='; 160 | } 161 | 162 | $this->provider->getQueryBuilder() 163 | ->where($property, $operator, $value); 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * {@inheritdoc} 170 | */ 171 | public function execute() 172 | { 173 | $result = $this->getProvider() 174 | ->getQueryBuilder() 175 | ->execute(); 176 | 177 | if ($this->queryType == static::$QUERY_SELECT) 178 | { 179 | return $this->getProvider() 180 | ->hydrate($result); 181 | } 182 | elseif ($this->queryType == static::$QUERY_INSERT and $this->insertModel instanceof ModelInterface) 183 | { 184 | // get the id and pass that to the model 185 | $id = $result[0]; 186 | // TODO: move this to the provider 187 | $this->insertModel['id'] = $id; 188 | } 189 | 190 | // Not directly needed but added for clarity 191 | return $result; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /src/QueryBuilder/Fuel.php: -------------------------------------------------------------------------------- 1 | connection = $connection; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function select($table, $columns = []) 53 | { 54 | $this->currentQuery = $this->connection 55 | ->selectArray($columns) 56 | ->from($table); 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function delete($table) 65 | { 66 | $this->currentQuery = $this->connection->delete($table); 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function insert($table, $row) 75 | { 76 | $this->currentQuery = $this->connection 77 | ->insert($table); 78 | 79 | if ($row instanceof ModelInterface) 80 | { 81 | $this->currentQuery->values($row->toArray()); 82 | } 83 | else if ($row instanceof ModelCollectionInterface or is_array($row)) 84 | { 85 | foreach ($row as $model) 86 | { 87 | $this->currentQuery->values($model->toArray()); 88 | } 89 | } 90 | else 91 | { 92 | // TODO: No clue what we have, complain about it. 93 | } 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * {@inheritdoc} 100 | */ 101 | public function where($column, $operator, $value) 102 | { 103 | if ($this->currentQuery === null) 104 | { 105 | throw new LogicException('ORM-006: You must start a query before you can filter it'); 106 | } 107 | 108 | $this->currentQuery->where($column, $operator, $value); 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * {@inheritdoc} 115 | */ 116 | public function count($table) 117 | { 118 | // TODO: Implement count() method. 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * {@inheritdoc} 125 | */ 126 | public function reset() 127 | { 128 | $this->currentQuery = null; 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * {@inheritdoc} 135 | */ 136 | public function execute() 137 | { 138 | // TODO Make this work right for count, delete, update and insert queries 139 | return $this->currentQuery->execute(); 140 | } 141 | 142 | /** 143 | * {@inheritdoc} 144 | */ 145 | public function update($table, $values) 146 | { 147 | $this->currentQuery = $this->connection->update($table); 148 | 149 | foreach ($values as $name => $value) 150 | { 151 | // TODO: Add proper PK checks in here 152 | if ($name !== 'id') 153 | { 154 | $this->currentQuery->set($name, $value); 155 | } 156 | } 157 | 158 | // TODO: Update to use the actual PK 159 | $this->where('id', '=', $values['id']); 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/QueryBuilderInterface.php: -------------------------------------------------------------------------------- 1 | keyFrom; 70 | } 71 | 72 | /** 73 | * @param string $keyFrom 74 | * 75 | * @since 2.0 76 | */ 77 | public function setKeyFrom($keyFrom) 78 | { 79 | $this->keyFrom = $keyFrom; 80 | } 81 | 82 | /** 83 | * @return string 84 | * 85 | * @since 2.0 86 | */ 87 | public function getProviderFrom() 88 | { 89 | return $this->providerFrom; 90 | } 91 | 92 | /** 93 | * @param string $providerFrom 94 | * 95 | * @since 2.0 96 | */ 97 | public function setProviderFrom($providerFrom) 98 | { 99 | $this->providerFrom = $providerFrom; 100 | } 101 | 102 | /** 103 | * @return string 104 | * 105 | * @since 2.0 106 | */ 107 | public function getKeyTo() 108 | { 109 | return $this->keyTo; 110 | } 111 | 112 | /** 113 | * @param string $keyTo 114 | * 115 | * @since 2.0 116 | */ 117 | public function setKeyTo($keyTo) 118 | { 119 | $this->keyTo = $keyTo; 120 | } 121 | 122 | /** 123 | * @return string 124 | * 125 | * @since 2.0 126 | */ 127 | public function getProviderTo() 128 | { 129 | return $this->providerTo; 130 | } 131 | 132 | /** 133 | * @param string $providerTo 134 | * 135 | * @since 2.0 136 | */ 137 | public function setProviderTo($providerTo) 138 | { 139 | $this->providerTo = $providerTo; 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/Relation/HasMany.php: -------------------------------------------------------------------------------- 1 | setKeyFrom($config['keyFrom']); 22 | $this->setKeyTo($config['keyTo']); 23 | $this->setProviderFrom($config['providerFrom']); 24 | $this->setProviderTo($config['providerTo']); 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function getModels(ModelInterface $modelFrom) 31 | { 32 | $provider = $modelFrom->getProvider() 33 | ->getFactory() 34 | ->get($this->getProviderTo()); 35 | 36 | $result = $provider 37 | ->getQuery() 38 | ->select() 39 | ->where($this->getKeyTo(), $modelFrom->{$this->getKeyFrom()}) 40 | ->execute(); 41 | 42 | // If the result is not a model collection then make sure one is returned for consistency 43 | if ( ! $result instanceof ModelCollectionInterface) 44 | { 45 | $result = $provider->forgeModelCollectionInstance([$result]); 46 | } 47 | 48 | return $result; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /tests/_bootstrap.php: -------------------------------------------------------------------------------- 1 | connection === null) 23 | { 24 | // Grab the DB config from codeception and create a DB instance we can use to talk to the database with 25 | $config = Configuration::config(); 26 | $dbConfig = $config['modules']['config']['Db']; 27 | /** @type Connection $fuelDBConnection */ 28 | $this->connection = \Fuel\Database\DB::connection( 29 | [ 30 | 'dsn' => $dbConfig['dsn'], 31 | 'username' => $dbConfig['user'], 32 | 'password' => $dbConfig['password'], 33 | ] 34 | ); 35 | } 36 | 37 | return $this->connection; 38 | } 39 | 40 | /** 41 | * Resets the DB connection 42 | */ 43 | public function resetDBInstance() 44 | { 45 | $this->connection = null; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /tests/_helpers/TestHelper.php: -------------------------------------------------------------------------------- 1 | alias = new Alias; 33 | } 34 | 35 | public function testTableAlias() 36 | { 37 | $name = 'mytable'; 38 | 39 | $this->assertEquals( 40 | 't0', 41 | $this->alias->aliasTable($name) 42 | ); 43 | } 44 | 45 | public function testTableMultipleAlias() 46 | { 47 | $name = 'mytable'; 48 | 49 | $this->assertEquals( 50 | 't0', 51 | $this->alias->aliasTable($name) 52 | ); 53 | 54 | $this->assertEquals( 55 | 't0', 56 | $this->alias->aliasTable($name) 57 | ); 58 | } 59 | 60 | public function testMultipleTableAlias() 61 | { 62 | $this->assertEquals( 63 | 't0', 64 | $this->alias->aliasTable('first table') 65 | ); 66 | 67 | $this->assertEquals( 68 | 't1', 69 | $this->alias->aliasTable('second table') 70 | ); 71 | } 72 | 73 | public function testReverseTableAlias() 74 | { 75 | $this->assertEquals( 76 | 't0', 77 | $this->alias->aliasTable('table') 78 | ); 79 | 80 | $this->assertEquals( 81 | 'table', 82 | $this->alias->reverseTableAlias('t0') 83 | ); 84 | } 85 | 86 | /** 87 | * @expectedException LogicException 88 | */ 89 | public function testInvalidReverseAlias() 90 | { 91 | $this->alias->reverseTableAlias('foobar'); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/unit/CodeGuy.php: -------------------------------------------------------------------------------- 1 | scenario->runStep(new \Codeception\Step\Action('getDbInstance', func_get_args())); 39 | } 40 | 41 | 42 | /** 43 | * [!] Method is generated. Documentation taken from corresponding module. 44 | * 45 | * Resets the DB connection 46 | * @see \Codeception\Module\CodeHelper::resetDBInstance() 47 | */ 48 | public function resetDBInstance() { 49 | return $this->scenario->runStep(new \Codeception\Step\Action('resetDBInstance', func_get_args())); 50 | } 51 | 52 | 53 | /** 54 | * [!] Method is generated. Documentation taken from corresponding module. 55 | * 56 | * Inserts SQL record into database. This record will be erased after the test. 57 | * 58 | * ``` php 59 | * haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com')); 61 | * ?> 62 | * ``` 63 | * 64 | * @param $table 65 | * @param array $data 66 | * 67 | * @return integer $id 68 | * @see \Codeception\Module\Db::haveInDatabase() 69 | */ 70 | public function haveInDatabase($table, $data) { 71 | return $this->scenario->runStep(new \Codeception\Step\Action('haveInDatabase', func_get_args())); 72 | } 73 | 74 | 75 | /** 76 | * [!] Method is generated. Documentation taken from corresponding module. 77 | * 78 | * Checks if a row with given column values exists. 79 | * Provide table name and column values. 80 | * 81 | * Example: 82 | * 83 | * ``` php 84 | * seeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com')); 86 | * 87 | * ``` 88 | * Will generate: 89 | * 90 | * ``` sql 91 | * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com' 92 | * ``` 93 | * Fails if no such user found. 94 | * 95 | * @param $table 96 | * @param array $criteria 97 | * Conditional Assertion: Test won't be stopped on fail 98 | * @see \Codeception\Module\Db::seeInDatabase() 99 | */ 100 | public function canSeeInDatabase($table, $criteria = null) { 101 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInDatabase', func_get_args())); 102 | } 103 | /** 104 | * [!] Method is generated. Documentation taken from corresponding module. 105 | * 106 | * Checks if a row with given column values exists. 107 | * Provide table name and column values. 108 | * 109 | * Example: 110 | * 111 | * ``` php 112 | * seeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com')); 114 | * 115 | * ``` 116 | * Will generate: 117 | * 118 | * ``` sql 119 | * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com' 120 | * ``` 121 | * Fails if no such user found. 122 | * 123 | * @param $table 124 | * @param array $criteria 125 | * @see \Codeception\Module\Db::seeInDatabase() 126 | */ 127 | public function seeInDatabase($table, $criteria = null) { 128 | return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInDatabase', func_get_args())); 129 | } 130 | 131 | 132 | /** 133 | * [!] Method is generated. Documentation taken from corresponding module. 134 | * 135 | * Effect is opposite to ->seeInDatabase 136 | * 137 | * Checks if there is no record with such column values in database. 138 | * Provide table name and column values. 139 | * 140 | * Example: 141 | * 142 | * ``` php 143 | * dontSeeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com')); 145 | * 146 | * ``` 147 | * Will generate: 148 | * 149 | * ``` sql 150 | * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com' 151 | * ``` 152 | * Fails if such user was found. 153 | * 154 | * @param $table 155 | * @param array $criteria 156 | * Conditional Assertion: Test won't be stopped on fail 157 | * @see \Codeception\Module\Db::dontSeeInDatabase() 158 | */ 159 | public function cantSeeInDatabase($table, $criteria = null) { 160 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInDatabase', func_get_args())); 161 | } 162 | /** 163 | * [!] Method is generated. Documentation taken from corresponding module. 164 | * 165 | * Effect is opposite to ->seeInDatabase 166 | * 167 | * Checks if there is no record with such column values in database. 168 | * Provide table name and column values. 169 | * 170 | * Example: 171 | * 172 | * ``` php 173 | * dontSeeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com')); 175 | * 176 | * ``` 177 | * Will generate: 178 | * 179 | * ``` sql 180 | * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com' 181 | * ``` 182 | * Fails if such user was found. 183 | * 184 | * @param $table 185 | * @param array $criteria 186 | * @see \Codeception\Module\Db::dontSeeInDatabase() 187 | */ 188 | public function dontSeeInDatabase($table, $criteria = null) { 189 | return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInDatabase', func_get_args())); 190 | } 191 | 192 | 193 | /** 194 | * [!] Method is generated. Documentation taken from corresponding module. 195 | * 196 | * Fetches a single column value from a database. 197 | * Provide table name, desired column and criteria. 198 | * 199 | * Example: 200 | * 201 | * ``` php 202 | * grabFromDatabase('users', 'email', array('name' => 'Davert')); 204 | * 205 | * ``` 206 | * 207 | * @version 1.1 208 | * 209 | * @param $table 210 | * @param $column 211 | * @param array $criteria 212 | * 213 | * @return mixed 214 | * @see \Codeception\Module\Db::grabFromDatabase() 215 | */ 216 | public function grabFromDatabase($table, $column, $criteria = null) { 217 | return $this->scenario->runStep(new \Codeception\Step\Action('grabFromDatabase', func_get_args())); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /tests/unit/ModelCollectionTest.php: -------------------------------------------------------------------------------- 1 | object = new ModelCollection; 33 | } 34 | 35 | public function testGetDefaultClass() 36 | { 37 | $this->assertEquals( 38 | '\Fuel\Orm\Model', 39 | $this->object->getModelClass() 40 | ); 41 | } 42 | 43 | public function testGetSetDefaultClass() 44 | { 45 | $class = '\stdClass'; 46 | 47 | $this->object->setModelClass($class); 48 | 49 | $this->assertEquals( 50 | $class, 51 | $this->object->getModelClass() 52 | ); 53 | } 54 | 55 | /** 56 | * @expectedException \InvalidArgumentException 57 | */ 58 | public function testSetInvalidDefaultClass() 59 | { 60 | $this->object->setModelClass(new \stdClass); 61 | } 62 | 63 | public function testSetModel() 64 | { 65 | $model = new Model; 66 | 67 | $this->object->set(0, $model); 68 | 69 | $this->assertEquals( 70 | $model, 71 | $this->object->get(0) 72 | ); 73 | } 74 | 75 | /** 76 | * @expectedException \InvalidArgumentException 77 | */ 78 | public function testSetWithNonObject() 79 | { 80 | $this->object->set(0, ''); 81 | } 82 | 83 | /** 84 | * @expectedException \InvalidArgumentException 85 | */ 86 | public function testSetWithInvalidObject() 87 | { 88 | $this->object->set(0, new \stdClass); 89 | } 90 | 91 | public function testCreateModelCollectionWithModels() 92 | { 93 | $models = [ 94 | new Model, 95 | new Model, 96 | new Model, 97 | ]; 98 | 99 | $collection = new ModelCollection($models); 100 | 101 | $this->assertEquals( 102 | $models, 103 | $collection->getContents() 104 | ); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /tests/unit/ModelTest.php: -------------------------------------------------------------------------------- 1 | object = new Model; 33 | } 34 | 35 | public function testIsNew() 36 | { 37 | $this->assertTrue( 38 | $this->object->isNew() 39 | ); 40 | 41 | $this->object->setIsNew(false); 42 | 43 | $this->assertFalse( 44 | $this->object->isNew() 45 | ); 46 | } 47 | 48 | /** 49 | * @expectedException \InvalidArgumentException 50 | */ 51 | public function testIsNewInvalid() 52 | { 53 | /** @noinspection PhpParamsInspection */ 54 | $this->object->setIsNew(new \stdClass()); 55 | } 56 | 57 | public function testGetOriginalData() 58 | { 59 | $this->assertInstanceOf( 60 | 'Fuel\Common\DataContainer', 61 | $this->object->getOriginalData() 62 | ); 63 | } 64 | 65 | public function testSetGetProvider() 66 | { 67 | /** @var \Fuel\Orm\ProviderInterface $provider */ 68 | $provider = Mockery::mock('Fuel\Orm\ProviderInterface'); 69 | 70 | $this->object->setProvider($provider); 71 | 72 | $this->assertEquals( 73 | $provider, 74 | $this->object->getProvider() 75 | ); 76 | } 77 | 78 | public function testConstructWithData() 79 | { 80 | $name = 'Test Model'; 81 | 82 | $data = [ 83 | 'name' => $name, 84 | ]; 85 | 86 | $object = new Model($data); 87 | 88 | $this->assertEquals( 89 | $data, 90 | $object->getOriginalData()->getContents() 91 | ); 92 | 93 | $this->assertEquals( 94 | $name, 95 | $object->name 96 | ); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /tests/unit/ProviderFactoryTest.php: -------------------------------------------------------------------------------- 1 | factory = new ProviderFactory; 32 | } 33 | 34 | public function testAddHasGet() 35 | { 36 | $name = 'provider'; 37 | 38 | $this->assertFalse( 39 | $this->factory->has($name) 40 | ); 41 | 42 | $this->factory->add($name, []); 43 | 44 | $this->assertTrue( 45 | $this->factory->has($name) 46 | ); 47 | 48 | $this->factory->remove($name); 49 | 50 | $this->assertFalse( 51 | $this->factory->has($name) 52 | ); 53 | } 54 | 55 | public function testGet() 56 | { 57 | $name = 'test'; 58 | $properties = ['id', 'name', 'created_at']; 59 | $tableName = 'oak_table'; 60 | 61 | $this->factory->add($name, $properties, $tableName); 62 | 63 | $provider = $this->factory->get($name); 64 | 65 | $this->assertInstanceOf( 66 | 'Fuel\Orm\Provider', 67 | $provider 68 | ); 69 | 70 | $this->assertEquals( 71 | $tableName, 72 | $provider->getTableName() 73 | ); 74 | 75 | $this->assertEquals( 76 | $properties, 77 | $provider->getProperties() 78 | ); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /tests/unit/ProviderTest.php: -------------------------------------------------------------------------------- 1 | provider = new \ProviderStub($db); 36 | } 37 | 38 | public function testGetProperties() 39 | { 40 | $this->assertEquals( 41 | ['a','b','c',], 42 | $this->provider->getProperties() 43 | ); 44 | } 45 | 46 | public function testGetModel() 47 | { 48 | $data = ['test']; 49 | $result = $this->provider->forgeModelInstance($data); 50 | 51 | // Make sure we have a model 52 | $this->assertInstanceOf( 53 | 'Fuel\Orm\Model', 54 | $result 55 | ); 56 | 57 | // Make sure the data has been set 58 | $this->assertEquals( 59 | $data, 60 | $result->getOriginalData()->getContents() 61 | ); 62 | 63 | // And make sure the provider has been set 64 | $this->assertEquals( 65 | $this->provider, 66 | $result->getProvider() 67 | ); 68 | } 69 | 70 | public function testGetModelClass() 71 | { 72 | $this->assertEquals( 73 | 'Fuel\Orm\Model', 74 | $this->provider->getModelClass() 75 | ); 76 | } 77 | 78 | /** 79 | * @expectedException \RuntimeException 80 | */ 81 | public function testGetModelClassInvalid() 82 | { 83 | $this->provider->setModelClass('\stdClass'); 84 | 85 | $this->provider->getModelClass(); 86 | } 87 | 88 | public function testGetModelCollectionClass() 89 | { 90 | $this->assertEquals( 91 | 'Fuel\Orm\ModelCollection', 92 | $this->provider->getModelCollectionClass() 93 | ); 94 | } 95 | 96 | public function testGetModelCollectionInstance() 97 | { 98 | $this->assertInstanceOf( 99 | 'Fuel\Orm\ModelCollection', 100 | $this->provider->forgeModelCollectionInstance() 101 | ); 102 | } 103 | 104 | public function testGetQuery() 105 | { 106 | $query = $this->provider->getQuery(); 107 | 108 | $this->assertInstanceOf( 109 | '\Fuel\Orm\Query', 110 | $query 111 | ); 112 | 113 | $this->assertEquals( 114 | $this->provider, 115 | $query->getProvider() 116 | ); 117 | } 118 | 119 | /** 120 | * @expectedException \RuntimeException 121 | */ 122 | public function testGetTableNameInvalid() 123 | { 124 | $this->provider->getTableName(); 125 | } 126 | 127 | public function testGetTableName() 128 | { 129 | $name = 'my_table'; 130 | $this->provider->setTableName($name); 131 | 132 | $this->assertEquals( 133 | $name, 134 | $this->provider->getTableName() 135 | ); 136 | } 137 | 138 | public function testHydrate() 139 | { 140 | $age = 32; 141 | $name = 'My Name'; 142 | 143 | $modelData = [[ 144 | 'name' => $name, 145 | 'age' => $age, 146 | ]]; 147 | 148 | /** @type ModelInterface $result */ 149 | $result = $this->provider->hydrate($modelData); 150 | 151 | $this->assertInstanceOf( 152 | 'Fuel\Orm\ModelInterface', 153 | $result 154 | ); 155 | 156 | $this->assertEquals( 157 | $age, 158 | $result->age 159 | ); 160 | 161 | $this->assertEquals( 162 | $name, 163 | $result->name 164 | ); 165 | } 166 | 167 | public function testHydrateWithMultipleModels() 168 | { 169 | $modelData = [ 170 | [ 171 | 'name' => 'name1', 172 | 'age' => 'age1', 173 | ], 174 | [ 175 | 'name' => 'name2', 176 | 'age' => 'age2', 177 | ], 178 | ]; 179 | 180 | /** @var \Fuel\Orm\ModelCollection $result */ 181 | $result = $this->provider->hydrate($modelData); 182 | 183 | $this->assertInstanceOf( 184 | '\Fuel\Orm\ModelCollection', 185 | $result 186 | ); 187 | 188 | $this->assertCount( 189 | 2, 190 | $result->getContents() 191 | ); 192 | } 193 | 194 | public function testAddGetRelation() 195 | { 196 | $relation = new AbstractRelationStub; 197 | $name = 'test'; 198 | 199 | $this->provider->addRelation($name, $relation); 200 | 201 | $this->assertEquals( 202 | $relation, 203 | $this->provider->getRelation($name) 204 | ); 205 | 206 | $this->assertEquals( 207 | [$name => $relation], 208 | $this->provider->getRelations() 209 | ); 210 | } 211 | 212 | /** 213 | * @expectedException InvalidArgumentException 214 | */ 215 | public function testGettingAnUnknownRelation() 216 | { 217 | $this->provider->getRelation('I do not exist'); 218 | } 219 | 220 | public function testGetSetFactory() 221 | { 222 | $this->assertNull( 223 | $this->provider->getFactory() 224 | ); 225 | 226 | /** @var \Fuel\Orm\ProviderFactory $factory */ 227 | $factory = \Mockery::mock('Fuel\Orm\ProviderFactory'); 228 | 229 | $this->provider->setFactory($factory); 230 | 231 | $this->assertEquals( 232 | $factory, 233 | $this->provider->getFactory() 234 | ); 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /tests/unit/QueryTest.php: -------------------------------------------------------------------------------- 1 | codeGuy->getDbInstance()); 50 | } 51 | 52 | public function testGetSetProvider() 53 | { 54 | /** @type Query $object */ 55 | /** @type ProviderInterface $provider */ 56 | list ($object, $provider) = $this->getInstance(); 57 | 58 | $this->assertEquals( 59 | $provider, 60 | $object->getProvider() 61 | ); 62 | 63 | $provider = Mockery::mock('Fuel\Orm\ProviderInterface'); 64 | 65 | $object->setProvider($provider); 66 | 67 | $this->assertEquals( 68 | $provider, 69 | $object->getProvider() 70 | ); 71 | } 72 | 73 | public function testSingleSelect() 74 | { 75 | $this->codeGuy->haveInDatabase('posts', [ 76 | 'id' => '1', 77 | 'title' => 'title', 78 | 'description' => 'description', 79 | 'created_at' => 123, 80 | 'updated_at' => 321, 81 | ]); 82 | 83 | $postProvider = new PostProvider($this->getQueryBuilder()); 84 | 85 | $result = $postProvider->getQuery() 86 | ->select() 87 | ->execute(); 88 | 89 | $this->assertEquals( 90 | 1, 91 | $result->id 92 | ); 93 | 94 | $this->assertEquals( 95 | 'title', 96 | $result->title 97 | ); 98 | 99 | $this->assertEquals( 100 | 'description', 101 | $result->description 102 | ); 103 | } 104 | 105 | public function testMultipleSelect() 106 | { 107 | $this->codeGuy->haveInDatabase('posts', [ 108 | 'id' => '1', 109 | 'title' => 'title', 110 | 'description' => 'description', 111 | 'created_at' => 123, 112 | 'updated_at' => 321, 113 | ]); 114 | $this->codeGuy->haveInDatabase('posts', [ 115 | 'id' => '2', 116 | 'title' => 'title2', 117 | 'description' => 'description2', 118 | 'created_at' => 456, 119 | 'updated_at' => 654, 120 | ]); 121 | 122 | $postProvider = new PostProvider($this->getQueryBuilder()); 123 | 124 | /** @type ModelCollection $result */ 125 | $result = $postProvider->getQuery() 126 | ->select() 127 | ->execute(); 128 | 129 | $this->assertInstanceOf( 130 | '\Fuel\Orm\ModelCollection', 131 | $result 132 | ); 133 | 134 | $this->assertCount( 135 | 2, 136 | $result->getContents() 137 | ); 138 | } 139 | 140 | public function testSingleDelete() 141 | { 142 | $model1 = [ 143 | 'id' => '1', 144 | 'title' => 'title', 145 | 'description' => 'description', 146 | 'created_at' => 123, 147 | 'updated_at' => 321, 148 | ]; 149 | $this->codeGuy->haveInDatabase('posts', $model1); 150 | 151 | $model2 = [ 152 | 'id' => '2', 153 | 'title' => 'title', 154 | 'description' => 'description', 155 | 'created_at' => 123, 156 | 'updated_at' => 321, 157 | ]; 158 | $this->codeGuy->haveInDatabase('posts', $model2); 159 | 160 | $provider = new PostProvider($this->getQueryBuilder()); 161 | 162 | $model = $provider->forgeModelInstance($model1); 163 | 164 | $provider->getQuery() 165 | ->delete([$model]) 166 | ->execute(); 167 | 168 | $this->codeGuy->cantSeeInDatabase( 169 | 'posts', 170 | $model1 171 | ); 172 | 173 | $this->codeGuy->canSeeInDatabase( 174 | 'posts', 175 | $model2 176 | ); 177 | } 178 | 179 | public function testMultipleDelete() 180 | { 181 | $modelData1 = [ 182 | 'id' => '1', 183 | 'title' => 'title', 184 | 'description' => 'description', 185 | 'created_at' => 123, 186 | 'updated_at' => 321, 187 | ]; 188 | $this->codeGuy->haveInDatabase('posts', $modelData1); 189 | 190 | $modelData2 = [ 191 | 'id' => '2', 192 | 'title' => 'title2', 193 | 'description' => 'description2', 194 | 'created_at' => 456, 195 | 'updated_at' => 654, 196 | ]; 197 | $this->codeGuy->haveInDatabase('posts', $modelData2); 198 | 199 | $provider = new PostProvider($this->getQueryBuilder()); 200 | 201 | $model1 = $provider->forgeModelInstance($modelData1); 202 | $model2 = $provider->forgeModelInstance($modelData2); 203 | 204 | $provider->getQuery() 205 | ->delete([$model1, $model2]) 206 | ->execute(); 207 | 208 | $this->codeGuy->cantSeeInDatabase('posts', $modelData1); 209 | $this->codeGuy->cantSeeInDatabase('posts', $modelData2); 210 | } 211 | 212 | public function testSingleInsert() 213 | { 214 | $model1 = [ 215 | 'title' => 'title', 216 | 'description' => 'description', 217 | 'created_at' => 123, 218 | 'updated_at' => 321, 219 | ]; 220 | 221 | $provider = new PostProvider($this->getQueryBuilder()); 222 | 223 | $model = $provider->forgeModelInstance($model1); 224 | 225 | $provider->getQuery() 226 | ->insert($model) 227 | ->execute(); 228 | 229 | $this->codeGuy->canSeeInDatabase('posts', $model1); 230 | $this->assertEquals('1', $model->id); 231 | } 232 | 233 | public function testMultipleInsert() 234 | { 235 | $modelData1 = [ 236 | 'id' => '1', 237 | 'title' => 'title', 238 | 'description' => 'description', 239 | 'created_at' => 123, 240 | 'updated_at' => 321, 241 | ]; 242 | $modelData2 = [ 243 | 'id' => '2', 244 | 'title' => 'title2', 245 | 'description' => 'description2', 246 | 'created_at' => 456, 247 | 'updated_at' => 654, 248 | ]; 249 | 250 | $provider = new PostProvider($this->getQueryBuilder()); 251 | 252 | $model1 = $provider->forgeModelInstance($modelData1); 253 | $model2 = $provider->forgeModelInstance($modelData2); 254 | 255 | $provider->getQuery() 256 | ->insert([$model1, $model2]) 257 | ->execute(); 258 | 259 | $this->codeGuy->canSeeInDatabase('posts', $modelData1); 260 | $this->codeGuy->canSeeInDatabase('posts', $modelData2); 261 | } 262 | 263 | public function testMultipleInsertWithCollection() 264 | { 265 | $modelData1 = [ 266 | 'id' => '1', 267 | 'title' => 'title', 268 | 'description' => 'description', 269 | 'created_at' => 123, 270 | 'updated_at' => 321, 271 | ]; 272 | $modelData2 = [ 273 | 'id' => '2', 274 | 'title' => 'title2', 275 | 'description' => 'description2', 276 | 'created_at' => 456, 277 | 'updated_at' => 654, 278 | ]; 279 | 280 | $provider = new PostProvider($this->getQueryBuilder()); 281 | 282 | $model1 = $provider->forgeModelInstance($modelData1); 283 | $model2 = $provider->forgeModelInstance($modelData2); 284 | 285 | $provider->getQuery() 286 | ->insert($provider->forgeModelCollectionInstance([$model1, $model2])) 287 | ->execute(); 288 | 289 | $this->codeGuy->canSeeInDatabase('posts', $modelData1); 290 | $this->codeGuy->canSeeInDatabase('posts', $modelData2); 291 | } 292 | 293 | public function testSelectWithWhere() 294 | { 295 | $modelData1 = [ 296 | 'id' => '1', 297 | 'title' => 'title', 298 | 'description' => 'description', 299 | 'created_at' => 123, 300 | 'updated_at' => 321, 301 | ]; 302 | $modelData2 = [ 303 | 'id' => '2', 304 | 'title' => 'title2', 305 | 'description' => 'description2', 306 | 'created_at' => 456, 307 | 'updated_at' => 654, 308 | ]; 309 | $this->codeGuy->haveInDatabase('posts', $modelData1); 310 | $this->codeGuy->haveInDatabase('posts', $modelData2); 311 | 312 | $provider = new PostProvider($this->getQueryBuilder()); 313 | 314 | $result = $provider->getQuery() 315 | ->select() 316 | ->where('id', '2') 317 | ->execute(); 318 | 319 | $this->assertInstanceOf( 320 | '\Fuel\Orm\Model', 321 | $result 322 | ); 323 | 324 | $this->assertEquals( 325 | 'title2', 326 | $result->title 327 | ); 328 | 329 | $this->assertEquals( 330 | 'description2', 331 | $result->description 332 | ); 333 | } 334 | 335 | /** 336 | * @expectedException LogicException 337 | */ 338 | public function testWhereWithoutQuery() 339 | { 340 | /** @type Query $query */ 341 | list($query, ) = $this->getInstance(); 342 | 343 | $query->where('foo', '<', 123); 344 | } 345 | 346 | public function testSingleUpdate() 347 | { 348 | $model1 = [ 349 | 'id' => '1', 350 | 'title' => 'title', 351 | 'description' => 'description', 352 | 'created_at' => 123, 353 | 'updated_at' => 321, 354 | ]; 355 | $this->codeGuy->haveInDatabase('posts', $model1); 356 | 357 | $provider = new PostProvider($this->getQueryBuilder()); 358 | $model = $provider->forgeModelInstance($model1); 359 | 360 | $model->title = 'shiny new title'; 361 | $provider->getQuery() 362 | ->update($model) 363 | ->execute(); 364 | 365 | $model1['title'] = 'shiny new title'; 366 | $this->codeGuy->canSeeInDatabase('posts', $model1); 367 | } 368 | 369 | } 370 | -------------------------------------------------------------------------------- /tests/unit/RelationHasManyTest.php: -------------------------------------------------------------------------------- 1 | factory = new ProviderFactory( 35 | new Fuel($this->codeGuy->getDbInstance()) 36 | ); 37 | 38 | $this->factory->add( 39 | 'posts', 40 | ['id', 'title', 'description', 'created_at', 'updated_at', 'author_id'], 41 | 'posts', 42 | [ 43 | 'hasMany' => [ 44 | 'comments' => [ 45 | 'providerTo' => 'comments', 46 | 'keyFrom' => 'id', 47 | 'keyTo' => 'post_id', 48 | ], 49 | ], 50 | ] 51 | ); 52 | 53 | $this->factory->add( 54 | 'comments', 55 | ['id', 'post_id', 'body'], 56 | 'comments' 57 | ); 58 | } 59 | 60 | public function testSelect() 61 | { 62 | $this->codeGuy->haveInDatabase('posts', [ 63 | 'id' => '1', 64 | 'title' => 'title', 65 | 'description' => 'description', 66 | 'created_at' => 123, 67 | 'updated_at' => 321, 68 | ]); 69 | 70 | $commentData = [ 71 | 'id' => '1', 72 | 'post_id' => '1', 73 | 'body' => 'Some interesting comment', 74 | ]; 75 | $this->codeGuy->haveInDatabase('comments', $commentData); 76 | 77 | $provider = $this->factory->get('posts'); 78 | $post = $provider 79 | ->getQuery() 80 | ->select() 81 | ->where('id', 1) 82 | ->select() 83 | ->execute(); 84 | 85 | $this->assertInstanceOf( 86 | 'Fuel\Orm\ModelCollectionInterface', 87 | $post->comments 88 | ); 89 | 90 | $this->assertEquals( 91 | $commentData, 92 | $post->comments[0]->get() 93 | ); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /tests/unit/_bootstrap.php: -------------------------------------------------------------------------------- 1 | modelClass = $class; 32 | } 33 | 34 | /** 35 | * Used to set the value of the table name property for testing 36 | * 37 | * @param string $name 38 | */ 39 | public function setTableName($name) 40 | { 41 | $this->tableName = $name; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/unit/stubs/Relation/AbstractRelationStub.php: -------------------------------------------------------------------------------- 1 |