# Generator Class

- [Overview](#1)
- [Properties](#3)
- [Methods](#5)
- [Generating Multiple Keys](#10)
- [Key Generation Logic](#12)
- [Generators](#13)

## Overview
The `Generator` class is a sub-class of the `AbstractGenerator` class, and also the parent class of all the built-in generators. It inherits all the properties and methods of the `AbstractGenerator` class, and provides specialised functionality for _key exclusions_ and handling the key generation logic, which includes: applying key transformations and adding affixes to generated keys. See [AbstractGenerator Class] for a complete list of the properties and methods available in the `AbstractGenerator` class.

> **`abstract` Class**

> The `Generator` class is declared as an abstract class by the `abstract` keyword. Hence, its constructor cannot be called with the `new` keyword. It is meant to be extended by specialised sub-classes.

######  

> **`keygen()` Method**   

> The `Generator` declares one `abstract protected` method, **`keygen(int $length)`** - which must be implemented by its sub-classes to provide specialised key generation logic. The `keygen()` method takes an `integer $length` parameter, and returns a random generated key of the given length.

## Properties

> **Inherited Properties**   

> The `Generator` class inherits all the properties of the `AbstractGenerator` class (see [AbstractGenerator Class] for list of the properties), and adds its own properties as follows:

#### `exclusions`
This is an `array` that contains a collection of keys that are blacklisted from being generated by the generator. If a key is generated that matches any of the keys in the `exclusions` collections, the generation logic is iterated until an allowed key is generated.

> **Key Iterations**   

> When a generated key exists on the `exclusions` collection, a new key generation iteration is run to generate another key. If the number of consecutive key iterations exceeds the `maxKeyIterations`, a `TooMuchKeyIterationsKeygenException` is thrown. The default value for the `maxKeyIterations` is `50`.

## Methods

> **Inherited Methods**   

> The `Generator` class inherits all the methods of the `AbstractGenerator` class (see [AbstractGenerator Class] for list of the methods), and adds its own methods as follows:   

######   

> **Return Values**   

> All methods of the `Generator` class, except the `generate()` method, return the generator instance on which they are called. This allows for the flexibility of using [method chaining] to execute methods on the generator.

#### `exclusion(array|string $key [...])`
The `exclusion()` method adds the specified key or collection of keys to the `exclusions` collection of the generator. The `$key` argument can be a key `string` or an `array` of keys.

#### `exclusions(array|string $key [...])`
The `exclusions()` method clears the `exclusions` collection and creates a fresh collection with the specified key or collection of keys. The `$key` argument can be a key `string` or an `array` of keys. If `$key` is set to an empty array (`[]`), the `exclusions` collection is emptied.

#### `generate([bool $disableAffixInclusion,] [callable|array $transformation [...]])`
The `Generator` class implements its own `generate()` method for handling the key generation logic and returning the generated key `string`. Its arguments are optional, hence, it can be called without arguments.

The argument(s) of the `generate()` method can be `callable` or `array` of callables that are temporarily appended to the `transformations` queue of the generator to be applied on the key to be generated. See [Key Transformations] for more details on applying key transformations.

If the first argument of the `generate()` method is a `boolean` value, it sets the `$disableAffixInclusion` flag - which temporarily overrides the _affix inclusion_ behaviour of the generator for the key to be generated. If it is set to `true`, affix inclusion is **disabled** - otherwise it is **enabled**. If the first argument is not `boolean`, the `$disableAffixInclusion` flag defaults to `false`.

##### Generating Multiple Keys
The `Generator` class is overloaded to provide dynamic methods that can be called to handle generation of multiple keys at once.

> **`generate20()`**   

> Assuming we want to generate 20 keys at once, we will call the `generate20()` method. The signature of this method is exactly the same as for the `generate()` method. It returns an `array` containing the generated keys - with count, according to the value of the `Size` decorator specified in the method identifier.

>However, if the value of the `Size` decorator is not a valid `(integer) >= 2`, an `UnknownMethodCallKeygenException` is thrown.

######   

> **`generateUnique20()`**

> When generating large number of multiple keys at once, it is possible that some keys may be repeated in the `array` of generated keys. To ensure that all the generated keys are unique, simply add the `Unique` decorator before the `Size` decorator in the method identifier. Hence, to generate 20 unique keys at once, we call the `generateUnique20()` method.

##### Key Generation Logic
The logic for key generation is defined as follows:

1. When the `generate()` method (or any of its variants) is called, its arguments are processed to resolve the **affix inclusion** behaviour and the **transformations queue** of callables that will be applied to the generated keys.

2. Next, the `keygen()` method is called on the generator with a resolved `$length` argument to generate a random key.

3. Next, the transformations are applied to the random key generated in **Step 2** starting from the first. The result of each transformation is passed to the next transformation on the queue.

4. Next, the affixes (prefix and suffix) are attached to the resulting key from **Step 3** as specified.

5. Finally, the resulting key from **Step 4** is checked to see if it exists on the `exclusions` collection. If it exists, the process jumps back to **Step 2** to run another key generation iteration, else, the generated key is returned.

> **Key Iterations**   

> When a generated key exists on the `exclusions` collection, a new key generation iteration is run to generate another key. If the number of consecutive key iterations exceeds the `maxKeyIterations`, the `generate()` method throws a `TooMuchKeyIterationsKeygenException`. The default value for the `maxKeyIterations` is `50`.

## Generators
Generators are simply sub-classes of the `Generator` class. They provide specialised key generation logic by implementing the `abstract keygen()` method inherited from the `Generator` class. The built-in generators that come with the Keygen package are all sub-classes of the `Generator` class. See [Built-In Generators] for more details about the built-in generators.


[AbstractGenerator Class]: <./abstract-generator.md>
[Built-In Generators]: <./generators.md>
[Key Transformations]: <./key-transformation.md>
[method chaining]: <https://en.wikipedia.org/wiki/Method_chaining>
