Browse Source

Refactor enum into trait.

mscherer 6 years ago
parent
commit
6893ad1bf6

+ 6 - 0
.editorconfig

@@ -16,3 +16,9 @@ end_of_line = crlf
 [*.yml]
 indent_style = space
 indent_size = 2
+
+[*.neon]
+indent_style = space
+
+[*.md]
+indent_style = space

+ 1 - 1
composer.json

@@ -46,7 +46,7 @@
 	},
 	"scripts": {
 		"phpstan": "phpstan analyse -c tests/phpstan.neon -l 3 src/",
-		"phpstan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.10.1 && mv composer.backup composer.json",
+		"phpstan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.11.1 && mv composer.backup composer.json",
 		"test": "php phpunit.phar",
 		"test-setup": "[ ! -f phpunit.phar ] && wget https://phar.phpunit.de/phpunit-6.5.13.phar && mv phpunit-6.5.13.phar phpunit.phar || true",
 		"test-coverage": "php phpunit.phar --log-junit webroot/coverage/unitreport.xml --coverage-html webroot/coverage --coverage-clover webroot/coverage/coverage.xml",

+ 2 - 2
docs/Behavior/AfterSave.md

@@ -19,8 +19,8 @@ $this->addBehavior('Tools.AfterSave', $options);
 Then inside your table you can do:
 ```php
 public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options) {
-	$entityBefore = $this->getEntityBeforeSave();
-	// Now you can check isDirty() etc
+    $entityBefore = $this->getEntityBeforeSave();
+    // Now you can check isDirty() etc
 }
 ```
 

+ 9 - 9
docs/Behavior/Bitmasked.md

@@ -46,13 +46,13 @@ const STATUS_FLAGGED = 8;
 ...
 
 public static function statuses($value = null) {
-	$options = [
-		self::STATUS_ACTIVE => __('Active'),
-		self::STATUS_FEATURED => __('Featured'),
-		self::STATUS_APPROVED => __('Approved'),
-		self::STATUS_FLAGGED => __('Flagged'),
-	];	
-	return parent::enum($value, $options);
+    $options = [
+        self::STATUS_ACTIVE => __('Active'),
+        self::STATUS_FEATURED => __('Featured'),
+        self::STATUS_APPROVED => __('Approved'),
+        self::STATUS_FLAGGED => __('Flagged'),
+    ];    
+    return parent::enum($value, $options);
 }
 ```
 
@@ -91,8 +91,8 @@ echo $this->Form->control('status', ['options' => Comment::statuses(), 'multiple
 And in your Table searchManager() setup:
 ```php
 $searchManager
-	// We need to map the posted "status" key to the finder required "bits" key
-	->finder('status', ['finder' => 'bits', 'map' => ['bits' => 'status']])
+    // We need to map the posted "status" key to the finder required "bits" key
+    ->finder('status', ['finder' => 'bits', 'map' => ['bits' => 'status']])
 ```
 
 This way the array of checkboxes selected will be turned into the integer bitmask needed for the query to work.

+ 5 - 5
docs/Behavior/Jsonable.md

@@ -18,7 +18,7 @@ Using 3.5+ you might not even need this anymore, as you can use type classes dir
 
         return $schema;
     }
-```	
+```    
 This is best combined with the Shim.Json type, as it properly handles `null` values:
 ```php
 // in bootstrap
@@ -76,7 +76,7 @@ The rest is CakePHP automagic :)
 
 ```php
 $this->addBehavior('Tools.Jsonable',
-	array('fields' => ['debug'], 'map' => ['geocoder_result']);
+    array('fields' => ['debug'], 'map' => ['geocoder_result']);
 ```
 I could access the array in the view as any other array since the behavior re-translates it back into an array on find().
 
@@ -96,13 +96,13 @@ We can switch to param style here globally for the entity:
 
 ```php
 $this->addBehavior('Tools.Jsonable',
-	['fields' => 'details', 'input' => 'param', 'output' => 'array']);
+    ['fields' => 'details', 'input' => 'param', 'output' => 'array']);
 ```
 
 Only for the add/edit action we need to also make "output" "param" at runtime:
 ```php
 $this->Table->behaviors()->Jsonable->options(
-	['fields' => 'details', 'input' => 'param', 'output' => 'param']);
+    ['fields' => 'details', 'input' => 'param', 'output' => 'param']);
 ```
 
 The form contains a "details" textarea field. We can insert:
@@ -122,7 +122,7 @@ debug($entity->get('details'));
 we can also simulate an ENUM by using
 ```php
 $this->addBehavior('Tools.Jsonable',
-	['fields' => 'tags', 'sort' => true, 'unique' => true, 'input' => 'list', 'output' => 'array']);
+    ['fields' => 'tags', 'sort' => true, 'unique' => true, 'input' => 'list', 'output' => 'array']);
 ```
 Dont' forget to use `'output' => 'list'` for add/edit actions.
 

+ 82 - 82
docs/Behavior/Passwordable.md

@@ -36,9 +36,9 @@ Also capable of:
 You can either pass those to the behavior at runtime, or globally via Configure and `app.php`:
 ```php
 $config = [
-	'Passwordable' => [
-		'passwordHasher' => ['className' => 'Fallback', 'hashers' => ['Default', 'Weak']]
-	]
+    'Passwordable' => [
+        'passwordHasher' => ['className' => 'Fallback', 'hashers' => ['Default', 'Weak']]
+    ]
 ]
 ```
 In this case we use the Fallback hasher class and both Default (Blowfish, CakePHP3 default) and Weak (E.g. sha1) hashing algorithms.
@@ -72,30 +72,30 @@ use Tools\Controller\Controller;
 
 class UsersController extends Controller {
 
-	public function register() {
-		$user = $this->Users->newEntity();
-		$this->Users->addBehavior('Tools.Passwordable');
+    public function register() {
+        $user = $this->Users->newEntity();
+        $this->Users->addBehavior('Tools.Passwordable');
 
 
-		if ($this->request->is(['put', 'post'])) {
-			$user = $this->Users->patchEntity($user, $this->request->getData());
-			$user->role_id = Configure::read('Roles.user');
+        if ($this->request->is(['put', 'post'])) {
+            $user = $this->Users->patchEntity($user, $this->request->getData());
+            $user->role_id = Configure::read('Roles.user');
 
-			if ($this->Users->save($user)) {
-				// Log in right away
-				$this->Auth->setUser($user->toArray());
-				// Flash message OK
-				return $this->redirect(['action' => 'index']);
-			}
-			// Flash message ERROR
+            if ($this->Users->save($user)) {
+                // Log in right away
+                $this->Auth->setUser($user->toArray());
+                // Flash message OK
+                return $this->redirect(['action' => 'index']);
+            }
+            // Flash message ERROR
 
-			// Pwd should not be passed to the view again for security reasons
-			$user->unsetProperty('pwd');
-			$user->unsetProperty('pwd_repeat');
-		}
+            // Pwd should not be passed to the view again for security reasons
+            $user->unsetProperty('pwd');
+            $user->unsetProperty('pwd_repeat');
+        }
 
-		$this->set(compact('user'));
-	}
+        $this->set(compact('user'));
+    }
 
 }
 ```
@@ -108,27 +108,27 @@ use Tools\Controller\Controller;
 
 class UsersController extends Controller {
 
-	public function edit() {
-		$uid = $this->request->getSession()->read('Auth.User.id');
-		$user = $this->Users->get($uid);
-		$this->Users->addBehavior('Tools.Passwordable', ['require' => false]);
-
-		if ($this->request->is(['put', 'post'])) {
-			$options = [
-				'fieldList' => [...]
-			];
-			$user = $this->Users->patchEntity($user, $this->request->getData(), $options);
-			if ($this->Users->save($user)) {
-				// Update session data, as well
-				$this->Auth->setUser($user->toArray());
-				// Flash message OK
-				return $this->redirect(['action' => 'index']);
-			}
-			// Flash message ERROR
-		}
-
-		$this->set(compact('user'));
-	}
+    public function edit() {
+        $uid = $this->request->getSession()->read('Auth.User.id');
+        $user = $this->Users->get($uid);
+        $this->Users->addBehavior('Tools.Passwordable', ['require' => false]);
+
+        if ($this->request->is(['put', 'post'])) {
+            $options = [
+                'fieldList' => [...]
+            ];
+            $user = $this->Users->patchEntity($user, $this->request->getData(), $options);
+            if ($this->Users->save($user)) {
+                // Update session data, as well
+                $this->Auth->setUser($user->toArray());
+                // Flash message OK
+                return $this->redirect(['action' => 'index']);
+            }
+            // Flash message ERROR
+        }
+
+        $this->set(compact('user'));
+    }
 
 }
 ```
@@ -139,32 +139,32 @@ We want to upgrade all accounts piece by piece upon login automatically. This wa
 without the user noticing:
 ```php
 public function login() {
-	if ($this->request->is(['put', 'post'])) {
-		$user = $this->Auth->identify();
-		if ($user) {
-			$this->Users->addBehavior('Tools.Passwordable', ['confirm' => false]);
-			$password = $this->request->data['password'];
-			$dbPassword = $this->Users->field('password', ['id' => $user['id']]);
-
-			if ($this->Users->needsPasswordRehash($dbPassword)) {
-				$data = [
-					'id' => $user['id'],
-					'pwd' => $password,
-					'modified' => false
-				];
-				$updatedUser = $this->Users->newEntity($data, ['markNew' => false]);
-				if (!$this->Users->save($updatedUser, ['validate' => false])) {
-					trigger_error(sprintf('Could not store new pwd for user %s.', $user['id']));
-				}
-			}
-			unset($user['password']);
-			$this->Auth->setUser($user);
-			// Flash message OK
-			return $this->redirect($this->Auth->redirectUrl());
-		}
-		// Flash message ERROR
-
-	}
+    if ($this->request->is(['put', 'post'])) {
+        $user = $this->Auth->identify();
+        if ($user) {
+            $this->Users->addBehavior('Tools.Passwordable', ['confirm' => false]);
+            $password = $this->request->data['password'];
+            $dbPassword = $this->Users->field('password', ['id' => $user['id']]);
+
+            if ($this->Users->needsPasswordRehash($dbPassword)) {
+                $data = [
+                    'id' => $user['id'],
+                    'pwd' => $password,
+                    'modified' => false
+                ];
+                $updatedUser = $this->Users->newEntity($data, ['markNew' => false]);
+                if (!$this->Users->save($updatedUser, ['validate' => false])) {
+                    trigger_error(sprintf('Could not store new pwd for user %s.', $user['id']));
+                }
+            }
+            unset($user['password']);
+            $this->Auth->setUser($user);
+            // Flash message OK
+            return $this->redirect($this->Auth->redirectUrl());
+        }
+        // Flash message ERROR
+
+    }
 }
 ```
 Note that the `passwordHasher` config has been set here globabally to assert the Fallback hasher class to kick in.
@@ -174,15 +174,15 @@ Note that the `passwordHasher` config has been set here globabally to assert the
 If the default rules don't satisfy your needs, you can add some more on top:
 ```php
 $rules = ['validateCustom' => [
-		'rule' => ['custom', '#^[a-z0-9]+$#'], // Just a test example, never use this regex!
-		'message' => __('Foo Bar'),
-		'last' => true,
-	],
-	'validateCustomExt' => [
-		'rule' => ['custom', '#^[a-z]+$#'], // Just a test example, never use this regex!
-		'message' => __('Foo Bar Ext'),
-		'last' => true,
-	]
+        'rule' => ['custom', '#^[a-z0-9]+$#'], // Just a test example, never use this regex!
+        'message' => __('Foo Bar'),
+        'last' => true,
+    ],
+    'validateCustomExt' => [
+        'rule' => ['custom', '#^[a-z]+$#'], // Just a test example, never use this regex!
+        'message' => __('Foo Bar Ext'),
+        'last' => true,
+    ]
 );
 $this->Users->Behaviors->load('Tools.Passwordable', ['customValidation' => $rules]);
 ```
@@ -197,7 +197,7 @@ The behavior will automatically add the internally needed fields to the `'fieldL
 So you only need to pass in the other non-password-related fields:
 ```php
 $options = [
-	'fieldList' => ['id', 'name']
+    'fieldList' => ['id', 'name']
 ];
 $user = $this->Users->patchEntity($user, $this->request->getData(), $options);
 ```
@@ -208,9 +208,9 @@ So if you do not want to force it, make sure your entity has those fields not pr
 ```php
 // Inside the entity
 protected $_accessible = [
-	'*' => false,
-	'pwd' => true,
-	...
+    '*' => false,
+    'pwd' => true,
+    ...
 ];
 
 // Or from the outside before patching

+ 2 - 2
docs/Behavior/Slugged.md

@@ -130,7 +130,7 @@ We want to store categories and we need a slug for nice SEO URLs like `/category
 
 ```php
 $this->addBehavior('Tools.Slugged',
-	['label' => 'name', 'unique' => true, 'mode' => 'ascii']
+    ['label' => 'name', 'unique' => true, 'mode' => 'ascii']
 );
 ```
 
@@ -150,7 +150,7 @@ Once that boolean checkbox is clicked it will then perform the slug update on sa
 If we just append the slug to the URL, such as `/category/123-[slugname]`, then we don't need to persist the slug.
 ```php
 $this->addBehavior('Tools.Slugged',
-	['label' => 'name', 'overwrite' => true, 'mode' => 'ascii', 'unique' => true]
+    ['label' => 'name', 'overwrite' => true, 'mode' => 'ascii', 'unique' => true]
 );
 ```
 Note that we don't need "unique" either then.

+ 11 - 11
docs/Behavior/String.md

@@ -11,8 +11,8 @@ Prevent using output modification if possible as it is done on every fetch.
 Include behavior in your Table class as
 ```php
 $this->addBehavior('Tools.String', [
-	'fields' => ['title'], 
-	'input' => ['ucfirst'],
+    'fields' => ['title'], 
+    'input' => ['ucfirst'],
 ]);
 ```
 This will `ucfirst()` the title prior to saving.
@@ -20,8 +20,8 @@ This will `ucfirst()` the title prior to saving.
 Tip: If you have other behaviors that might modify the array data prior to saving, better use a lower (higher value) priority:
 ```php
 $this->addBehavior('Tools.String', [
-	...
-	'priority' => 11,
+    ...
+    'priority' => 11,
 ]);
 ```
 
@@ -32,8 +32,8 @@ If string that function is expected to exist. You can also use callables and ano
 Instead of the preferred input formatting you can also modify the output (for each find):
 ```php
 $this->addBehavior('Tools.String', [
-	...
-	'output' => ['ucfirst'],
+    ...
+    'output' => ['ucfirst'],
 ]);
 ```
 
@@ -42,16 +42,16 @@ $this->addBehavior('Tools.String', [
 
 Imagine the following config:
 ```php
-	'fields' => ['title', 'comment'], 
-	'input' => ['strtolower', 'ucwords'],
+    'fields' => ['title', 'comment'], 
+    'input' => ['strtolower', 'ucwords'],
 ```
 
 And the input:
 ```php
 $data = [
-	'title' => 'some nAme',
-	'comment' => 'myBlog',
-	'url' => 'www.dereuromark.de',
+    'title' => 'some nAme',
+    'comment' => 'myBlog',
+    'url' => 'www.dereuromark.de',
 ];
 $comment = $this->Comments->newEntity($data);
 $result = $this->Comments->save($comment);

+ 3 - 3
docs/Behavior/Toggle.md

@@ -12,9 +12,9 @@ On delete it will give the toggle status to another record if applicable.
 Include behavior in your Table class as
 ```php
 $this->addBehavior('Tools.Toggle', [
-	'field' => 'primary', 
-	'scopeFields' => ['user_id'],
-	'scope' => [],
+    'field' => 'primary', 
+    'scopeFields' => ['user_id'],
+    'scope' => [],
 ]);
 ```
 

+ 2 - 2
docs/Behavior/Typographic.md

@@ -14,8 +14,8 @@ See the [TypographyHelper](/docs/Helper/Typography.md) docs for output modificat
 Include behavior in your Table class as
 ```php
 $this->addBehavior('Tools.Typographic', [
-	'fields' => ['content'], 
-	'mergeQuotes' => false,
+    'fields' => ['content'], 
+    'mergeQuotes' => false,
 ]);
 ```
 

+ 5 - 5
docs/Component/Mobile.md

@@ -11,8 +11,8 @@ Just store the user's choice in the `'User.mobile'` session key.
 
 ## Configuration
 
-	'on' => 'beforeFilter', // initialize (prior to controller's beforeRender) or startup
-	'engine' => null, // CakePHP internal if null
-	'themed' => false, // If false uses subfolders instead of themes: /View/.../mobile/
-	'auto' => false, // auto set mobile views
-	
+    'on' => 'beforeFilter', // initialize (prior to controller's beforeRender) or startup
+    'engine' => null, // CakePHP internal if null
+    'themed' => false, // If false uses subfolders instead of themes: /View/.../mobile/
+    'auto' => false, // auto set mobile views
+    

+ 69 - 0
docs/Entity/Enum.md

@@ -0,0 +1,69 @@
+# EnumTrait
+
+Enum support via trait and `enum()` method.
+
+Add the trait to your entity:
+```php
+use Tools\Model\Entity\EnumTrait;
+
+class MyEntity extends Entity {
+
+    use EnumTrait;
+```
+
+Then add your enums like so:
+
+```php
+    /**
+     * @param int|array|null $value
+     *
+     * @return array|string
+     */
+    public static function statuses($value = null) {
+        $options = [
+            static::STATUS_PENDING => __('Pending'),
+            static::STATUS_SUCCESS => __('Success'),
+            static::STATUS_FAILURE => __('Failure'),
+        ];
+        return parent::enum($value, $options);
+    }
+
+    public const STATUS_PENDING = 0;
+    public const STATUS_SUCCESS = 1;
+    public const STATUS_FAILURE = 2;    
+```
+
+You can now use it in the forms in your templates:
+```php
+<?= $this->Form->create($entity) ?>
+...
+<?= $this->Form->control('status', ['options' => $entity::statuses()]) ?>
+```
+
+And in your index or view:
+```php
+echo $entity::statuses($entity->status);
+```
+
+Make sure the property is not null (or it would return an array). Best to check for it before or combine 
+it with Shim plugin GetTrait and `$entity->getStatusOrFail()`:
+
+```php
+// Allowed to be empty
+echo $entity->status !== null ? $entity::statuses($entity->status) : $default;
+
+// Required or throw exception
+echo $entity::statuses($entity->getStatusOrFail());
+```
+
+
+## Bake template support
+
+Use the [Setup](https://github.com/dereuromark/cakephp-setup) plugin (`--theme Setup`) to 
+get auto-support for your templates based on the existing enums you added.
+
+The above form controls would be auto-added by this.
+
+## Background
+
+See [Static Enums](http://www.dereuromark.de/2010/06/24/static-enums-or-semihardcoded-attributes/).

+ 16 - 16
docs/Error/ErrorHandler.md

@@ -7,25 +7,25 @@ Most 404 logs should not be part of your error log, for example.
 You can either completely ignore them, or better yet put them into their own space:
 ```php
 Log::config('404', [
-	'className' => '...', // e.g. 'File' or 'DatabaseLog.Database'
-	'type' => '404',
-	'levels' => ['error'],
-	'scopes' => ['404'],
+    'className' => '...', // e.g. 'File' or 'DatabaseLog.Database'
+    'type' => '404',
+    'levels' => ['error'],
+    'scopes' => ['404'],
 ]);
 ```
 
 Make sure your other log configs are scope-deactivated then to prevent them being logged twice:
 ```php
-	'Log' => [
-		'debug' => [
-			'scopes' => false,
-			...
-		],
-		'error' => [
-			'scopes' => false,
-			...
-		],
-	],
+    'Log' => [
+        'debug' => [
+            'scopes' => false,
+            ...
+        ],
+        'error' => [
+            'scopes' => false,
+            ...
+        ],
+    ],
 ```
 
 In your bootstrap, the following snippet just needs to include the ErrorHandler of this plugin:
@@ -34,9 +34,9 @@ In your bootstrap, the following snippet just needs to include the ErrorHandler
 use Tools\Error\ErrorHandler;
 
 if ($isCli) {
-	(new ConsoleErrorHandler(Configure::read('Error')))->register();
+    (new ConsoleErrorHandler(Configure::read('Error')))->register();
 } else {
-	(new ErrorHandler(Configure::read('Error')))->register();
+    (new ErrorHandler(Configure::read('Error')))->register();
 }
 ```
 

+ 1 - 1
docs/Helper/Common.md

@@ -6,7 +6,7 @@ A CakePHP helper to handle some common topics.
 Include helper in your AppView class as
 ```php
 $this->addHelper('Tools.Common', [
-	...
+    ...
 ]);
 ```
 

+ 8 - 8
docs/Helper/Form.md

@@ -20,13 +20,13 @@ Alternatively, you can enable it in your AppView class.
 ```php
 // Inside your app.php config:
 $config = [
-	'debug' => true,
-	...
-	'FormConfig' => array(
-		'novalidate' => true,
-		'templates' => array(
-			'dateWidget' => '{{day}}{{month}}{{year}}{{hour}}{{minute}}{{second}}{{meridian}}',
-		)
-	)
+    'debug' => true,
+    ...
+    'FormConfig' => array(
+        'novalidate' => true,
+        'templates' => array(
+            'dateWidget' => '{{day}}{{month}}{{year}}{{hour}}{{minute}}{{second}}{{meridian}}',
+        )
+    )
 ];
 ```

+ 12 - 12
docs/Helper/Format.md

@@ -6,7 +6,7 @@ A CakePHP helper to handle some common format topics.
 Include helper in your AppView class as
 ```php
 $this->addHelper('Tools.Format', [
-	...
+    ...
 ]);
 ```
 
@@ -17,23 +17,23 @@ You can store default configs also in Configure key `'Format'`.
 Display font icons using the default namespace or an already prefixed one.
 ```php
 echo $this->Html->link(
-	$this->Format->icon('view'), 
-	$url, 
-	$attributes
+    $this->Format->icon('view'), 
+    $url, 
+    $attributes
 );
 ```
 
 You can alias them via Configure for more usability:
 ```php
 // In app.php
-	'Format' => [
-		'fontIcons' => [
-			'login' => 'fa fa-sign-in',
-			'logout' => 'fa fa-sign-out',
-			'translate' => 'fa fa-language',
-		],
-	],
-	
+    'Format' => [
+        'fontIcons' => [
+            'login' => 'fa fa-sign-in',
+            'logout' => 'fa fa-sign-out',
+            'translate' => 'fa fa-language',
+        ],
+    ],
+    
 // in the template
 echo $this->Format->icon('translate', ['title' => 'Translate this']);
 ```

+ 12 - 12
docs/Helper/Tree.md

@@ -14,7 +14,7 @@ then use all properties and getters on that object.
 Include helper in your AppView class as
 ```php
 $this->addHelper('Tools.Tree', [
-	...
+    ...
 ]);
 ```
 
@@ -42,11 +42,11 @@ That template can then contain all normal template additions, including full hel
  */
 
 if (!$data->visible) { // You can do anything here depending on the record content
-	return;
+    return;
 }
 $label = $data->title;
 if ($activePathElement) {
-	$label .= ' (active)';
+    $label .= ' (active)';
 }
 ?>
 <li>
@@ -78,12 +78,12 @@ Here the same keys are available on the first argument (`$data` array). So the a
 `$data['data']` and usually be the entity. 
 If you are passing entities, it helps to inline annotate in this case:
 ```php
-	$closure = function(array $data) {
-		/** @var \Cake\ORM\Entity $entity */
-		$entity = $data['data'];
+    $closure = function(array $data) {
+        /** @var \Cake\ORM\Entity $entity */
+        $entity = $data['data'];
 
-		return h($entity->name) . ($data['activePathElement'] ? ' (active)' : '');
-	};
+        return h($entity->name) . ($data['activePathElement'] ? ' (active)' : '');
+    };
 ```
 
 ### Active path
@@ -96,16 +96,16 @@ $tree = $this->Table->find('threaded')->toArray();
 
 // The current active element in the tree (/view/6)
 $id = 6;
-		
+        
 // We need to get the current path for this element
 $nodes = $this->Table->find('path', ['for' => $id]);
 $path = $nodes->extract('id')->toArray();
 
 // In your view
 $options = [
-	'autoPath' => [$current->lft, $current->rght], 
-	'treePath' => $path, 
-	'element' => 'tree', // src/Template/Element/tree.ctp
+    'autoPath' => [$current->lft, $current->rght], 
+    'treePath' => $path, 
+    'element' => 'tree', // src/Template/Element/tree.ctp
 ];
 echo $this->Tree->generate($tree, $options);
 ```

+ 1 - 1
docs/Helper/Typography.md

@@ -14,7 +14,7 @@ Upon output one can the decide to re-apply localization here.
 Include helper in your AppView class as
 ```php
 $this->addHelper('Tools.Typography', [
-	...
+    ...
 ]);
 ```
 

+ 33 - 33
docs/I18n/I18n.md

@@ -6,9 +6,9 @@ from routing to controller logic and view outputs to URL building and redirectin
 ## Basics
 Set up a default language in your configs:
 ```php
-	'Config' => [
-		'language' => 'de',
-	],
+    'Config' => [
+        'language' => 'de',
+    ],
 ```
 Any `Configure::read('Config.language')` or `I18n::getLocale()` call should return that default language.
 
@@ -29,36 +29,36 @@ Note: When you have intl installed, you can also try to use the CakePHP core Loc
 ## Session based language switch
 In your AppController you can now do:
 ```php
-	/**
-	 * @return void
-	 */
-	public function initialize() {
-		parent::initialize();
-
-		// First check the session
-		$language = $this->request->getSession()->read('Config.language');
-		// Then check the browser preference for the whitelisted languages
-		if (!$language) {
-			$language = Language::findFirstMatch(Configure::read('Config.supportedLanguages'));
-		}
-		// Overwrite the system default
-		if ($language) {
-			Configure::write('Config.language', substr($language, 0, 2));
-			I18n::setLocale($language);
-		}
+    /**
+     * @return void
+     */
+    public function initialize() {
+        parent::initialize();
+
+        // First check the session
+        $language = $this->request->getSession()->read('Config.language');
+        // Then check the browser preference for the whitelisted languages
+        if (!$language) {
+            $language = Language::findFirstMatch(Configure::read('Config.supportedLanguages'));
+        }
+        // Overwrite the system default
+        if ($language) {
+            Configure::write('Config.language', substr($language, 0, 2));
+            I18n::setLocale($language);
+        }
 ```
 
 You then just need a switch on the website that allows the other to change the language (by writing it into the session):
 ```php
 <?php if ($this->Configure->read('Config.language') === 'de') {
-	echo $this->Html->image('flag_de.png', ['title' => __('German')]);
+    echo $this->Html->image('flag_de.png', ['title' => __('German')]);
 } else {
-	echo $this->Form->postLink($this->Html->image('flag_de.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'de'], ['block' => true, 'escape' => false, 'title' => __('German')]);
+    echo $this->Form->postLink($this->Html->image('flag_de.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'de'], ['block' => true, 'escape' => false, 'title' => __('German')]);
 } ?>
 <?php if ($this->Configure->read('Config.language') === 'en') {
-	echo $this->Html->image('flag_en.png', ['title' => __('English')]);
+    echo $this->Html->image('flag_en.png', ['title' => __('English')]);
 } else {
-	echo $this->Form->postLink($this->Html->image('flag_en.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'en'], ['block' => true, 'escape' => false, 'title' => __('English')]);
+    echo $this->Form->postLink($this->Html->image('flag_en.png'), ['prefix' => false, 'plugin' => 'Tools', 'controller' => 'ShuntRequest', 'action' => 'language', 'en'], ['block' => true, 'escape' => false, 'title' => __('English')]);
 }?>
 ```
 
@@ -80,15 +80,15 @@ $language = $this->request->getParam('language');
 And make sure your routes are all adjusted to accept and parse the language param:
 ```php
 Router::scope('/', function (RouteBuilder $routes) {
-	$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
-
-	$routes->connect(
-		'/:language/:controller/:action/*',
-		[],
-		['language' => 'de']
-	);
-	
-	...
+    $routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
+
+    $routes->connect(
+        '/:language/:controller/:action/*',
+        [],
+        ['language' => 'de']
+    );
+    
+    ...
 }
 ```
 

+ 1 - 1
docs/Install.md

@@ -28,7 +28,7 @@ or
 
 ```php
 Plugin::loadAll([
-		'Tools' => ['bootstrap' => true]
+        'Tools' => ['bootstrap' => true]
 ]);
 ```
 

+ 14 - 14
docs/Mailer/Email.md

@@ -30,19 +30,19 @@ Email::config(Configure::consume('Email'));
 They will read from Configure what you defined there, e.g for sending SMTP mails.
 ```
 'Email' => array(
-	'default' => array(
-		'from' => 'your@email.com'
-	)
+    'default' => array(
+        'from' => 'your@email.com'
+    )
 ),
 'EmailTransport' => array(
-	'default' => array(
-		'className' => 'Smtp',
-		'host' => 'smtp.hostname.com',
-		'username' => 'your@email.com',
-		'password' => 'yourpwd',
-		'tls' => true,
-		'port' => 587
-	)
+    'default' => array(
+        'className' => 'Smtp',
+        'host' => 'smtp.hostname.com',
+        'username' => 'your@email.com',
+        'password' => 'yourpwd',
+        'tls' => true,
+        'port' => 587
+    )
 )
 ```
 
@@ -67,10 +67,10 @@ $email->viewVars(compact('message', 'other'));
 
 // Send it
 if ($email->send()) {
-	// Success
+    // Success
 } else {
-	// Error
-	// You can use $email->getError() and display it in debug mode or log it away
+    // Error
+    // You can use $email->getError() and display it in debug mode or log it away
 }
 ```
 `from` is already set with your admin email by default, if you configured `Config.adminEmail`.

+ 5 - 2
docs/README.md

@@ -54,6 +54,9 @@ Helpers:
 Widgets:
 * [Datalist](Widget/Datalist.md)
 
+Entity:
+* [Enum](Entity/Enum.md)
+
 ## Basic enhancements of the core
 
 ### Model
@@ -87,9 +90,9 @@ use Tools\Controller\Controller;
 
 class AppController extends Controller {
 
-	public $components = ['Tools.Common'];
+    public $components = ['Tools.Common'];
 
-	public $helpers = ['Tools.Common', 'Tools.Time', 'Tools.Number', 'Tools.Format'];
+    public $helpers = ['Tools.Common', 'Tools.Time', 'Tools.Number', 'Tools.Format'];
 
 }
 ```

+ 2 - 2
docs/Shims.md

@@ -33,7 +33,7 @@ use Tools\Controller\Controller;
 
 class AppController extends Controller {
 
-	public $components = ['Shim.Session'];
+    public $components = ['Shim.Session'];
 
 }
 ```
@@ -52,7 +52,7 @@ use Tools\Controller\Controller;
 
 class AppController extends Controller {
 
-	public $helpers = ['Shim.Session'];
+    public $helpers = ['Shim.Session'];
 
 }
 ```

+ 18 - 18
docs/TestSuite/Testing.md

@@ -44,8 +44,8 @@ that it's still the real deal.
 $this->Api = new ApiClass();
 
 if (!$this->isDebug()) {
-	$this->Api = $this->getMock('ApiClass');
-	$this->Api->expects(...)->...;
+    $this->Api = $this->getMock('ApiClass');
+    $this->Api->expects(...)->...;
 }
 ```
 
@@ -74,22 +74,22 @@ use Tools\TestSuite\TestCase;
 
 class FooBarShellTest extends TestCase {
 
-	/**
-	 * @return void
-	 */
-	public function setUp() {
-		parent::setUp();
-
-		$this->out = new ConsoleOutput();
-		$this->err = new ConsoleOutput();
-		$io = new ConsoleIo($this->out, $this->err);
-
-		$this->Shell = $this->getMock(
-			'App\Shell\FooBarShell',
-			['in', '_stop'],
-			[$io]
-		);
-	}
+    /**
+     * @return void
+     */
+    public function setUp() {
+        parent::setUp();
+
+        $this->out = new ConsoleOutput();
+        $this->err = new ConsoleOutput();
+        $io = new ConsoleIo($this->out, $this->err);
+
+        $this->Shell = $this->getMock(
+            'App\Shell\FooBarShell',
+            ['in', '_stop'],
+            [$io]
+        );
+    }
 ```
 Note that we mock the `in` and `_stop` methods, though, to allow handling those by mocking them out in the test cases.
 

+ 3 - 4
src/Mailer/Email.php

@@ -119,17 +119,16 @@ class Email extends CakeEmail {
 	}
 
 	/**
-	 * EmailLib::resetAndSet()
-	 *
-	 * @return void
+	 * @return $this
 	 */
 	public function reset() {
-		parent::reset();
 		$this->_priority = null;
 		$this->_wrapLength = null;
 
 		$this->_error = null;
 		$this->_debug = null;
+
+		return parent::reset();
 	}
 
 	/**

+ 1 - 26
src/Model/Entity/Entity.php

@@ -6,31 +6,6 @@ use Cake\ORM\Entity as CakeEntity;
 
 class Entity extends CakeEntity {
 
-	/**
-	 * The main method for any enumeration, should be called statically
-	 * Now also supports reordering/filtering
-	 *
-	 * @link https://www.dereuromark.de/2010/06/24/static-enums-or-semihardcoded-attributes/
-	 * @param string|array|null $value Integer or array of keys or NULL for complete array result
-	 * @param array $options Options
-	 * @param string|null $default Default value
-	 * @return string|array
-	 */
-	public static function enum($value, array $options, $default = null) {
-		if ($value !== null && !is_array($value)) {
-			if (array_key_exists($value, $options)) {
-				return $options[$value];
-			}
-			return $default;
-		}
-		if ($value !== null) {
-			$newOptions = [];
-			foreach ($value as $v) {
-				$newOptions[$v] = $options[$v];
-			}
-			return $newOptions;
-		}
-		return $options;
-	}
+	use EnumTrait;
 
 }

+ 34 - 0
src/Model/Entity/EnumTrait.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Tools\Model\Entity;
+
+trait EnumTrait {
+
+	/**
+	 * The main method for any enumeration, should be called statically
+	 * Now also supports reordering/filtering
+	 *
+	 * @link https://www.dereuromark.de/2010/06/24/static-enums-or-semihardcoded-attributes/
+	 * @param string|array|null $value Integer or array of keys or NULL for complete array result
+	 * @param array $options Options
+	 * @param string|null $default Default value
+	 * @return string|array
+	 */
+	public static function enum($value, array $options, $default = null) {
+		if ($value !== null && !is_array($value)) {
+			if (array_key_exists($value, $options)) {
+				return $options[$value];
+			}
+			return $default;
+		}
+		if ($value !== null) {
+			$newOptions = [];
+			foreach ($value as $v) {
+				$newOptions[$v] = $options[$v];
+			}
+			return $newOptions;
+		}
+		return $options;
+	}
+
+}

+ 1 - 1
src/Shell/InflectShell.php

@@ -41,7 +41,7 @@ class InflectShell extends Shell {
 	/**
 	 * Inflects words
 	 *
-	 * @return void
+	 * @return bool|int|null
 	 */
 	public function main() {
 		if (!empty($this->args)) {

+ 10 - 10
tests/phpstan.neon

@@ -1,14 +1,14 @@
 parameters:
-	autoload_files:
-		- %rootDir%/../../../tests/bootstrap.php
-	excludes_analyse:
-		- %rootDir%/../../../src/TestSuite/*
-		- %rootDir%/../../../src/View/Helper/TreeHelper
-		- %rootDir%/../../../src/Utility/Mime
-	ignoreErrors:
-		- '#Access to an undefined property .+Table::\$belongsTo#'
-		- '#Call to an undefined method .+TimeHelper::.+\(\)#'
-		- '#Access to protected property .+ServerRequest::\$.+#'
+    autoload_files:
+    - %rootDir%/../../../tests/bootstrap.php
+    excludes_analyse:
+        - %rootDir%/../../../src/TestSuite/*
+        - %rootDir%/../../../src/View/Helper/TreeHelper
+        - %rootDir%/../../../src/Utility/Mime
+    ignoreErrors:
+        - '#Access to an undefined property .+Table::\$belongsTo#'
+        - '#Call to an undefined method .+TimeHelper::.+\(\)#'
+        - '#Access to protected property .+ServerRequest::\$.+#'
 
 services:
     -