Adding custom type in CakePHP 4.x

I want to adding custom type in specific column field. This part is still encrypt-decrypt specific column field used AES-256, here’s below src\Database\Type\CryptedType.php

namespace App\Database\Type;

use Cake\Database\DriverInterface;
use Cake\Database\Type\BaseType;
use Cake\Utility\Security;
use Cake\Database\TypeInterface;


class CryptedType extends BaseType
{
	public function toDatabase($value, DriverInterface $driver)
	{
		return Security::encrypt($value, Security::getSalt());
	}
	
	public function toPHP($value, DriverInterface $driver)
	{
		if($value === null) {
			return null;
		}
		return Security::decrypt($value, Security::getSalt());
	}
}

next I call above in config\bootstrap.php

<?php
Type::map('crypted', 'App\Database\Type\CryptedType');

when I run test on http://localhost/baksoganteng/users the error message display below

Fatal error: Class App\Database\Type\CryptedType contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Cake\Database\TypeInterface::marshal) in C:\xampp\htdocs\baksoganteng\src\Database\Type\CryptedType.php on line 10
Warning (512): Unable to emit headers. Headers sent in file=C:\xampp\htdocs\baksoganteng\src\Database\Type\CryptedType.php line=10 [CORE\src\Http\ResponseEmitter.php, line 71]
Warning (2): Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\baksoganteng\src\Database\Type\CryptedType.php:10) [CORE\src\Http\ResponseEmitter.php, line 168]
Warning (2): Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\baksoganteng\src\Database\Type\CryptedType.php:10) [CORE\src\Http\ResponseEmitter.php, line 197]

Error Class App\Database\Type\CryptedType contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Cake\Database\TypeInterface::marshal)

File C:\xampp\htdocs\baksoganteng\src\Database\Type\CryptedType.php

Line 10

thanx for someone that’s want to help me

Does this answer your question?

there’s still error, Zuluru

4. use Cake\Database\DriverInterface;
5. use Cake\Database\Type\BaseType;
6. use Cake\Utility\Security;
7. use Cake\Database\TypeInterface::marshal;

class CryptedType extends BaseType
{

Error in: ROOT\src\Database\Type\CryptedType.php, line 7

where’s the part I will to be fix…??

implement the remaining methods means you need to add that missing method to your class.

see e.g. cakephp/FloatType.php at 4.x · cakephp/cakephp · GitHub

this is basic PHP OOP knowledge so either try learning more about that via googleing it or use an IDE which helps you do those basic OOP things automatically for you like PHPStorm or VSCode (with addons)

so in general you NEED to implement/add every function mentioned in the interface to your class

because the BaseType class (which your CryptedType extends from) implements that interface

thanx for guide, I was follow guide above and added a few line below
\src\Database\Type\CryptedType.php

<?php
namespace App\Database\Type;

use Cake\Database\DriverInterface;
use Cake\Utility\Security;
use Cake\Database\TypeInterface;
use PDO;


class CryptedType implements TypeInterface
{
	public function toDatabase($value, DriverInterface $driver)
	{
		return Security::encrypt($value, Security::getSalt());
	}
	
	public function toPHP($value, DriverInterface $driver)
	{
		if($value === null) {
			return null;
		}
		return Security::decrypt($value, Security::getSalt());
	}

	public function getBaseType(): ?string
    {
        return $this->_name;
    }
	
	public function toStatement($value, DriverInterface $driver)
    {
        if ($value === null) {
            return PDO::PARAM_NULL;
        }

        return PDO::PARAM_STR;
    }
	
	public function marshal($value)
    {
        if ($value === null || $value === '') {
            return null;
        }
        if (is_string($value) && $this->_useLocaleParser) {
            return $this->_parseValue($value);
        }
        if (is_numeric($value)) {
            return (float)$value;
        }
        if (is_string($value) && preg_match('/^[0-9,. ]+$/', $value)) {
            return $value;
        }

        return null;
    }
	
	public function newId()
    {
        return null;
    }
	
	public function getName(): ?string
    {
        return $this->_name;
    }
}

but while run test, there’s error display below

App\Model\Table\UsersTable::beforeFind(): Argument #4 ($primary) must be of type Cake\Table\boolean, bool given, called in C:\xampp\htdocs\baksoganteng\vendor\cakephp\cakephp\src\Event\EventManager.php on line 309
TypeError

where’s the part I should be fix in \Table\UsersTable.php

<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\Event\Event;
use ArrayObject;
use Cake\Utility\Security;
use Cake\Database\Schema\Table as Schema;
use Cake\Database\Type\BaseType;
use Cake\Table\boolean;
use Cake\Database\Schema\TableSchemaInterface;
use Cake\Database\Type\ColumnSchemaAwareInterface;
use Cake\Datasource\ResultSetInterface;
use Cake\Datasource\EntityInterface;
use Cake\Collection\CollectionInterface;

class UsersTable extends Table
{

public function beforeFind(Event $event, Query $query, ArrayObject $options, boolean $primary): beforeFind
	{
		
		$query->formatResults(
			function($results) {
				return $results->map(function ($row) {
					foreach($this->encryptedFields as $fieldName) {
						if(isset($row[$fieldName])) {
							$row[$fieldName] = Security::decrypt($row[$fieldName], Security::getSalt());
						}
					}
					return $row;
				});
			}
		);
	}

}

boolean is not the real type, its bool
See PHP: Type declarations - Manual