Configuration Options

You can change the behaviour of various features by setting configuration options.

Objectiphy attempts to behave in a sensible way for the majority of use cases, but there might be times when you want to change the default behaviour. There are two types of configuration options - things that apply globally, and things that are restricted to a particular entity.

Setting Config Options

All of the available global configuration options are defined as class constants on the ConfigOptions class, and you can set them by calling the setConfigOption method on a repository and passing the option name, and value, like this:

use Objectiphy\Objectiphy\Config\ConfigOptions;

$repository->setConfigOption(
    ConfigOptions::BIND_TO_ENTITIES, 
    false
);

Similarly, if you want to set a configuration option for a particular entity, you can call the setEntityConfigOption method, passing the entity class name, option name, and value, like this:

use Objectiphy\Objectiphy\Config\ConfigEntity;

$repository->setEntityConfigOption(
    MyEntity::class,
    EntityConfig::COLLECTION_TYPE, 
    MyCollection::class
);

Global Config Options

The following global configuration options are available.

DEV_MODE (boolean): Whether or not we are running in a development environment. When in development mode, any existing proxy object files are destroyed when the repository factory is created (this is to allow for the fact that the structure of your entities may change during development). When set to false, a cache directory must be specified. You would not typically need to set this as a config option, as you should pass it to the repository factory constructor as the third argument.

RECORD_QUERIES (boolean): Whether or not to store a list of all queries executed and SQL generated for debugging purposes. When in development mode, this will default to true, and in production it will default to false. If you specify a value of true or false yourself though, that will override the default behaviour, thus enabling you to either suppress recording the queries in development, or to start recording them in production. The queries are only stored in memory for the duration of the request, and are not persisted. To access recorded queries, use either the getSql method or the getExplanation method on the respository (see troubleshooting).

CACHE_DIRECTORY (string): Location of a writable directory where proxy class files (and other cache files) can be stored. To enable lazy-loading, Objectiphy has to generate proxy classes that extend your entities. In order for PHP to recognise these proxy classes, Objectiphy must write code files that can then be included by PHP. In production mode, mapping information is also stored in cache files. These files have to be written to the file system, so you must supply a directory that is writable by the user PHP runs under. It is not safe to use the /tmp directory on a production server, as the PHP garbage collector could delete proxy files before they have finished being used. Also, you should choose a directory which is not publicly accessible. You would not typically need to set this as a config option, as you should pass it to the repository factory constructor as the second argument.

SERIALIZATION_GROUPS (array): Array of strings representing the serialization groups to hydrate. If you use serialization groups to limit which properties are returned in your API responses, you might not always need to load all of the data for the entire entity, as it will not be used. In such cases, you can tell Objectiphy about the groups that you are interested in, and it will only hydrate the data for properties in those groups, thus improving performance.

HYDRATE_UNGROUPED_PROPERTIES (boolean): Whether or not to hydrate properties that do not have a serialization group (only applies if one or more serialization groups have been specified). Default is true.

GUESS_MAPPINGS (boolean): Whether or not to attempt to guess the names of tables and columns based on their class and property names, if no explicit name has been specified. Default is true. You can specify a naming strategy to use to work out the table/column names - the default naming strategy assumes that your properties use camelCase and your database tables and columns use snake_case. If you want Objectiphy to only use explicitly mapped table and column names, set this to false.

TABLE_NAMING_STRATEGY (NamingStrategyInterface): A concrete instance of a naming strategy class to use when guessing table names. You can pass any instantiated object that implements NamingStrategyInterface.

COLUMN_NAMING_STRATEGY (NamingStrategyInterface): A concrete instance of a naming strategy class to use when guessing column names. You can pass any instantiated object that implements NamingStrategyInterface.

DEFAULT_COLLECTION_CLASS (string): The name of a collection class to use when populating a to-many relationship. Default is 'array'. If you have your own custom collection class that you want to use for collections of child objects, you can specify that here, and Objectiphy will create a collection of your specified type when hydrating to-many relationships. You could specify Doctrine's ArrayCollection class here if you want. When using a custom collection class, if your collection cannot be created simply by passing an array to the constructor, you will also need to create a collection factory (that implements CollectionFactoryInterface), and set that on the RepositoryFactory before you create your repositories. You can also specify the collection class to use for a specific parent entity using the entity config option as described below, or for a particular property on the relationship mapping.

ALLOW_DUPLICATES (boolean): Whether or not to allow duplicate entities to be returned in a response. This option is not yet supported - duplicates are currently always allowed. Default is true. For certain types of queries with joins, it is possible for the join to cause duplicate records to be returned. To avoid this, you can set this flag to false which will cause Objectiphy to group by the primary key of the main entity as well as all foreign keys. Depending on your query and MySQL version, this could cause SQL errors if there is any ambiguity about which fields to return. In that case, you might need to re-think your query, or use the MySQL ANY_VALUE function on the affected field(s).

EAGER_LOAD_TO_ONE (boolean): Whether to eager load one-to-one and many-to-one relationships by default. Default is true. Relationships that join to a single child entity can usually be loaded using a join - meaning that a single query can load multiple entities. This is usually more efficient than lazy loading, which would require a separate query to load each child. Lazy loading would only be more efficient if the child property does not get accessed (and the lazy load therefore never happens). You can specify whether to lazy load or eager load on each relationship, but this configuration option allows you to set the default behaviour. EAGER_LOAD_TO_MANY (boolean): Whether to eager load one-to-many and many-to-many relationships by default. Default is false. Relationships that join to a multiple child entities cannot be loaded using a join (as that would cause duplicate parent records), so are always 'late bound' - that is, a separate query is run to fetch them. There is usually no advantage to running that extra query until such time as the property is accessed, but if you want to ensure that all data is loaded immediately, you can set this to true - this will cause the additional query to be run immediately rather than waiting until the property is accessed. You can specify whether to lazy load or eager load on each relationship, but this configuration option allows you to set the default behaviour.

DISABLE_DELETE_RELATIONSHIPS (boolean): Whether to prevent relationships from being deleted. Default is false. If you rarely or never delete data from your database via your application, you can tell Objectiphy to disable relationships and entities from being deleted. This acts both as a safety feature to prevent accidental data deletion, but can also have performance benefits, as it will not be necessary to check whether any items are missing and would therefore normally require deletion. This config option controls whether relationships can be deleted (ie. the value of a join column being set to null) - there is a separate option to control whether entities can be deleted (ie. rows deleted from the database) - see below.

DISABLE_DELETE_ENTITIES (boolean): Whether to prevent entities from being deleted. Default is false. If you rarely or never delete data from your database via your application, you can tell Objectiphy to disable entity deletion. This acts both as a safety feature to prevent accidental data deletion, but can also have performance benefits, as it will not be necessary to check whether any items are missing and would therefore normally require deletion. This config option controls whether entities can be deleted (ie. rows deleted from the database) - there is a separate option to control whether relationships can be deleted (ie. the value of a join column being set to null) - see above.

BIND_TO_ENTITIES (boolean): Whether to hydrate and return entities based on the data loaded from the database. Default is true. If this is set to false, data will be returned in flat arrays rather than hydrated into hierarchical objects. Returning arrays is much faster, but defeats the purpose of using an ORM, as the whole point is to hydrate entities. Still, it can be useful at times if entities are not needed, for example when exporting data to a CSV file.

ENTITY_CONFIG (array): Array of entity configuration objects, keyed on entity class name. You do not normally need to use this option as you can handle entity configuration using the separate setEntityConfigOption method, as described above.

SAVE_CHILDREN_BY_DEFAULT (boolean): Whether to save changes to child objects when a parent object is saved. Default is true. If this is set to false, the default behaviour will change to ignore child objects when a parent object is saved. However, regardless of whether this config option is true or false, you can specify whether or not to save child objects at the time you call the saveEntity method, by passing true or false to the second parameter. DISABLE_ENTITY_CACHE (boolean): Whether to stop Objectiphy from tracking changes to objects and force it to re-load entities from the database even if it has already loaded them in a previous request. Default is false. Whenever Objectiphy hydrates an entity, it stores a reference to the entity and a cloned copy in its entity tracker (as PHP uses copy-on-write, this should have no impact on memory usage until something is changed on the entity). If the same entity is requested again, rather than look it up in the database and hydrate it all over again, Objectiphy will just return the cached entity. It also uses the clone to check for changes when you ask for an entity to be saved, and only saves the items that have changed since it was cloned. If you disable the entity cache with this config option, the entity tracker will be cleared down before each call, thus disabling those features (the entity tracker will still be used within each call to prevent unlimited recursion though).

MAX_DEPTH (int | null): The maximum depth of child objects to fetch in a single query. Default is 3. When early binding to-one relationships where the child entity also has a child entity, and that child also has a child, etc., this option specifies how deep to go before stopping and requiring that further children be lazy loaded. The actual results you get back from any query will not change if you change this figure, only the number of queries that are used to fetch them. If you need to traverse the entire hierarchy of objects, it might be more efficient to load the entire hierarchy in one go, in which case you can set this to 0 (zero). There is a risk with complex hierarchies however that loading the entire depth will result in reaching the MySQL join limit, or running out of memory. A lower figure for max_depth will result in a faster initial query, but perhaps more lazy-loads. If you do not necessarily need the entire hierarchy, a lower figure will be more efficient. The default value of 3 tries to strike a balance between these options, but you might get better performance with a higher or lower value.

Entity Config Options

Entity configuration options are applied only to one particular entity. The following entity config options are available.

TABLE_OVERRIDES (array): Override values for table mapping information. Default is empty. See the separate page on mapping overrides.

COLUMN_OVERRIDES (array): Override values for column mapping information. Default is empty. See the separate page on mapping overrides.

RELATIONSHIP_OVERRIDES (array): Override values for relationship mapping information. Default is empty. See the separate page on mapping overrides.

COLLECTION_CLASS (string): Name of class to use for hydrating collections of entities on to-many relationships. Default is 'array' or whatever is specified on the global config option as described above. If an entity has several to-many child objects, you can specify a collection class to use for all of them here. Alternatively, you can specify them individually on relationship mappings, or globally using the global config option. ENTITY_FACTORY (EntityFactoryInterface): Factory instance to use for creating the entity. By default, Objectiphy will try to instantiate new entities directly, without passing any constructor arguments, but if you need a factory to create instances of a particular entity, you can pass your factory in on this entity config option, and Objectiphy will defer to your factory to create entities of that type.

Defining Default Options

There is a performance impact in setting config options, as it might require re-loading the mapping information for a class (although cached mapping information minimises the effect of this). If you always want certain configuration options to be set, you can set them on the repository factory before you create any repositories - that way, the settings you specify become the default, and no re-loading of mapping information is necessary. You can tell the factory which settings to use by default by passing a .ini file to the factory in its constructor.

There is a sample config.ini file in Objectiphy's root directory - this is not actually used, it is just provided as an example. You can put your .ini file anywhere (but preferably somewhere that it won't get overwritten when you run composer update - so not in the vendor folder!). To tell Objectiphy to use your .ini file as the default options, you can pass it to the repository factory as shown below.

$iniFile = __DIR__ . '/objectiphy.ini';
$factory = new RepositoryFactory($pdo, '/var/cache', false, $iniFile);

Of course, more typically, you would be using a dependency injection container, so in Symfony it might look more like this:

Objectiphy\Objectiphy\Factory\RepositoryFactory:
    arguments:
        $pdo: '@PDO'
        $cacheDirectory: '%kernel.cache_dir%'
        $devMode: '%kernel.debug%'
        $configIniFile: '%path_to_ini_file%'

Last updated