И так, в продолжение к предыдущему посту о использовании сущностей в Codeigniter 4.

Что случилось с предыдущим примером? Для начала все свойства нашего класса должны были быть общедоступными, чтобы позволить ему работать с Model. Хотя это не самая худшая вещь в мире, она определенно не идеальна.

Что случилось с предыдущим примером? Для начала все свойства нашего класса должны были быть общедоступными, чтобы позволить ему работать с Model. Хотя это не самая худшая вещь в мире, она определенно не идеальна.

Геттеры и сеттеры

Первый шаг - сделать свойства класса protected(защищенными), а не public (публичными). Чтобы сделать видимыми для Model, мы будем использовать магические методы __get () и __set () для обеспечения доступа.

public function __get(string $key)
{
    if (isset($this->$key))
    {
        return $this->$key;
    }
}

public function __set(string $key, $value = null)
{
    if (isset($this->$key))
        
    {

        $this->$key = $value;
      
    }
}

 

Это не решает нашу проблему, а просто добавляет дополнительный код между значением и вашим кодом, что хорошо для инкапсуляции, но мы можем сделать его лучше. Это будет происходить много раз, когда вы хотите выполнять некоторую логику всякий раз, когда мы ценим сущность. Например, вы можете захотеть автоматически хешировать пароль всякий раз, когда он установлен. Или вы можете всегда сохранять свои даты в качестве экземпляров DateTime. Итак, как мы это делаем?

Для этого добавим некоторые новые функции в сеттер, который позволяет нам вызывать любой метод с именем set_, а затем имя свойства, например set_password.

public function __set(string $key, $value = null)
{
    // if a set* method exists for this key,
       
    // use that method to insert this value.
       
    $method = 'set_'.$key;
     
    if (method_exists($this, $method))
     
    {
          
        $this->$method($value);
        
    }
      
    // A simple insert on existing keys otherwise.
     
    elseif (isset($this->$key))
        
    {
          
        $this->$key = $value;
      
    }

}

Теперь вы можете решить свои задачи с помощью простых небольших функций, таких как:
 

protected function set_password(string $value)
{
    $this->password = password_hash($value, PASSWORD_BCRYPT);
}

protected function set_last_login(string $value)
{
    $this->last_login = new DateTime($value);
}

Всякий раз, когда вы устанавливаете $user->password = 'abc', или $user->last_login = '10 -15-2016 3:42 pm ', ваши пользовательские методы будут автоматически вызваны, хранение имущества по мере необходимости. Давайте сделаем то же самое для геттеров.

public function __get(string $key)
 
{
          
    // if a set* method exists for this key,
       
    // use that method to insert this value.
       
    if (method_exists($this, $key))
        
    {
              
        return $this->$key();
      
    }

         
    if (isset($this->$key))
        
    {
          
        return $this->$key;
        
    }
  
}

В этом случае мы просто проверяем метод с точным именем как свойство класса. Вы можете установить эти методы как общедоступные, а затем он будет работать одинаково, независимо от того, был ли он вызван как метод или свойство, $user->last_login или $user->last_login():

public function last_login($format=‘Y-m-d H:i:s’)
{
    return $this->last_login->format($format);
}

Установив значение по умолчанию для $format, оно работает в любом случае, но теперь вы можете получить значение в нужном вам формате в любое время, а не ограничиваться одним форматом.

Filler

Это уже помогло нашим классам стать более способными и гибкими, в то же время помогая нам поддерживать наши бизнес-правила и все еще легко сохраняться в базе данных и снова возвращаться обратно. Но разве было бы неплохо, если бы мы могли просто перетащить массив пар ключ / значение в класс и заполнить ли эти свойства автоматически, но только работать с существующими свойствами? Это упрощает захват данных из $ _POST, создает новый класс Entity и заталкивает его перед сохранением. Еще лучше, если мы сможем настроить данные таким же образом, как и с сеттерами, не так ли? Добро пожаловать в метод fill():

public function fill(array $data)
  
{
          
    foreach ($data as $key => $var)
        
    {
              
        $method = 'fill_'. $key;
           
        if (method_exists($this, $method))
         
        {
              
            $this->$method($var);
          
        }

         
        elseif (property_exists($this, $key))
          
        {
              
            $this->$key = $var;
            
        }
      
    }
  
}

Быстрый пример должен сделать это понятным. Сначала давайте возьмем данные POST, добавим его в новый объект User и сохраним его в базе данных:

$data = $_POST;
$user = new App\Entities\User();
$user->fill($data);
$userModel->save($user);

Если бы это была форма регистрации, которую мы обрабатывали, мы могли бы получить поле password, чтобы удостовериться, что оно было хэшировано. Итак, быстрый метод fill_, и дальше нам хорошо. В этом примере мы просто повторно используем созданный нами сеттер:

protected function fill_password(string $value)_
{
    $this->set_password($value);
}

Entity Class

Чтобы сделать это простым для повторного использования, мы должны создать новый класс Entity, который может расширить наши сущности и получить эти функции автоматически. Вот один из таких классов, который также заботится о наших временных отметках, в том числе о часовых поясах.

<?php namespace Myth;

/**
 * Class Entity
 *
 * A base class for entities that provides some convenience methods
 * that make working with entities a little simpler.
 *
 * @package App\Entities
 */
class Entity
{
    /**
     * Given an array of key/value pairs, will fill in the
     * data on this instance with those values. Only works
     * on fields that exist.
     *
     * @param array $data
     */
    public function fill(array $data)
    {
        foreach ($data as $key => $var)
        {
            $method = 'fill_'. $key;
            if (method_exists($this, $method))
            {
                $this->$method($var);
            }

            elseif (property_exists($this, $key))
            {
                $this->$key = $var;
            }
        }
    }

    //--------------------------------------------------------------------

    //--------------------------------------------------------------------
    // Getters
    //--------------------------------------------------------------------

    /**
     * Returns the created_at field value as a string. If $format is
     * a string it will be used to format the result by. If $format
     * is TRUE, the underlying DateTime option will be returned instead.
     *
     * Either way, the timezone is set to the value of $this->timezone,
     * if set, or to the app's default timezone.
     *
     * @param string $format
     *
     * @return string
     */
    public function created_at($format = 'Y-m-d H:i:s'): string
    {
        $timezone = isset($this->timezone)
            ? $this->timezone
            : app_timezone();

        $this->created_at->setTimezone($timezone);

        return $format === true
            ? $this->created_at
            : $this->created_at->format($format);
    }

    //--------------------------------------------------------------------

    /**
     * Returns the updated_at field value as a string. If $format is
     * a string it will be used to format the result by. If $format
     * is TRUE, the underlying DateTime option will be returned instead.
     *
     * Either way, the timezone is set to the value of $this->timezone,
     * if set, or to the app's default timezone.
     *
     * @param string $format
     *
     * @return string
     */
    public function updated_at($format = 'Y-m-d H:i:s'): string
    {
        $timezone = isset($this->timezone)
            ? $this->timezone
            : app_timezone();

        $this->updated_at->setTimezone($timezone);

        return $format === true
            ? $this->updated_at
            : $this->updated_at->format($format);
    }

    //--------------------------------------------------------------------

    //--------------------------------------------------------------------
    // Setters
    //--------------------------------------------------------------------

    /**
     * Custom value for the `created_at` field used with timestamps.
     *
     * @param string $datetime
     *
     * @return $this
     */
    public function set_created_at(string $datetime)
    {
        $this->created_at = new \DateTime($datetime, new \DateTimeZone('UTC'));

        return $this;
    }

    //--------------------------------------------------------------------

    /**
     * Custom value for the `updated_at` field used with timestamps.
     *
     * @param string $datetime
     *
     * @return $this
     */
    public function set_updated_at(string $datetime)
    {
        $this->updated_at = new \DateTime($datetime, new \DateTimeZone('UTC'));

        return $this;
    }

    //--------------------------------------------------------------------

    //--------------------------------------------------------------------
    // Magic
    //--------------------------------------------------------------------

    /**
     * Allows Models to be able to get any class properties that are
     * stored on this class.
     *
     * For flexibility, child classes can create `get*()` methods
     * that will be used in place of getting the value directly.
     * For example, a `created_at` property would have a `created_at`
     * method.
     *
     * @param string $key
     *
     * @return mixed
     */
    public function __get(string $key)
    {
        // if a set* method exists for this key,
        // use that method to insert this value.
        if (method_exists($this, $key))
        {
            return $this->$key();
        }

        if (isset($this->$key))
        {
            return $this->$key;
        }
    }

    //--------------------------------------------------------------------

    /**
     * Allows Models to be able to set any class properties
     * from the result set.
     *
     * For flexibility, child classes can create `set*()` methods
     * to provide custom setters for keys. For example, a field
     * named `created_at` would have a `set_created_at` method.
     *
     * @param string $key
     * @param null   $value
     */
    public function __set(string $key, $value = null)
    {
        // if a set* method exists for this key,
        // use that method to insert this value.
        $method = 'set_'.$key;
        if (method_exists($this, $method))
        {
            $this->$method($value);
        }

        // A simple insert on existing keys otherwise.
        elseif (isset($this->$key))
        {
            $this->$key = $value;
        }
    }

    //--------------------------------------------------------------------
}

 

Ссылки по теме

Источник: Better Entities in CodeIgniter 4