Как заинжектить трейт в объект

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.21, 19:25

zelenin писал(а):
2017.04.21, 19:22
pistol писал(а):
2017.04.21, 19:19
Я все это веду к тому, что если будут использовать не $this, а $this->owner, то можно будет по-старому инжектить методы трейтов:

Код: Выделить всё

$object->attachTrait();
так как инжектить? пример выше - это обычное использование трейтов. там же нет динамического аттача.
При вызове несуществующего метода, можно возвращать одноименный метод из приаттаченных трейтов.
Если во всех трейтах будет использоваться $this->owner вместо $this и заюзан Yii\\base\Trait, можно гарантировать одинаковый результат работы трейтов приаттаченых нормально и динамически.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как заинжектить трейт в объект

Сообщение zelenin » 2017.04.21, 19:30

pistol писал(а):
2017.04.21, 19:25
zelenin писал(а):
2017.04.21, 19:22
pistol писал(а):
2017.04.21, 19:19
Я все это веду к тому, что если будут использовать не $this, а $this->owner, то можно будет по-старому инжектить методы трейтов:

Код: Выделить всё

$object->attachTrait();
так как инжектить? пример выше - это обычное использование трейтов. там же нет динамического аттача.
При вызове несуществующего метода, можно возвращать одноименный метод из приаттаченных трейтов.
это то, ради чего трейты были созданы.
pistol писал(а):
2017.04.21, 19:25
Если во всех трейтах будет использоваться $this->owner вместо $this и заюзан Yii\\base\Trait, можно гарантировать одинаковый результат работы трейтов приаттаченых нормально и динамически.
я спрашиваю, где вы динамически аттачите трейты? трейты не аттачатся динамически. и $this->owner не нужен.

Аватара пользователя
ElisDN
Сообщения: 5399
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение ElisDN » 2017.04.21, 19:32

pistol писал(а):
2017.04.21, 19:25
При вызове несуществующего метода, можно возвращать одноименный метод из приаттаченных трейтов.
Предлагаете инжектить коллбэки в трейт, чтобы магией их оттуда вызывать?

P.S. Трейты не настраиваются и на события не навешиваются, поэтому поведения они никогда не заменят.

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.21, 19:45

zelenin писал(а):
2017.04.21, 19:30
я спрашиваю, где вы динамически аттачите трейты? трейты не аттачатся динамически. и $this->owner не нужен.
В yii\base\Component, как и раньше (магией __call). Вот только как вытащить метод из трейта - хз, инстанс трейта не создается, только если рефлексией как-то. Попробую ради интереса.
ElisDN писал(а):
2017.04.21, 19:32
pistol писал(а):
2017.04.21, 19:25
При вызове несуществующего метода, можно возвращать одноименный метод из приаттаченных трейтов.
Предлагаете инжектить коллбэки в трейт, чтобы магией их оттуда вызывать?

P.S. Трейты не настраиваются и на события не навешиваются, поэтому поведения они никогда не заменят.
А вот настройки - да, даже теоритических идей нет, как это сделать.

Всем спасибо. Понял, что не получится использовать коллбеки как раньше.
Ждем выхода нового YII :)
Последний раз редактировалось pistol 2017.04.21, 19:47, всего редактировалось 1 раз.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как заинжектить трейт в объект

Сообщение zelenin » 2017.04.21, 19:47

pistol писал(а):
2017.04.21, 19:45
zelenin писал(а):
2017.04.21, 19:30
я спрашиваю, где вы динамически аттачите трейты? трейты не аттачатся динамически. и $this->owner не нужен.
В yii\base\Component, как и раньше
да код покажите. не аттачатся же.
pistol писал(а):
2017.04.21, 19:45
только как вытащить метод из трейта - хз, инстанс трейта не создается, только если рефлексией как-то. Попробую ради интереса.
так о том и речь, что обсуждаем то, чего нет.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как заинжектить трейт в объект

Сообщение zelenin » 2017.04.21, 19:49

их и не надо аттачить. Поведения много где использовались, но теперь есть для каждого использования поведений современные кейсы.
например к моделям AR - обычные трейты, поведения реквеста - миддлвари итд.

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.21, 19:56

zelenin писал(а):
2017.04.21, 19:49
их и не надо аттачить. Поведения много где использовались, но теперь есть для каждого использования поведений современные кейсы.
например к моделям AR - обычные трейты, поведения реквеста - миддлвари итд.
Подумал еще немного - действительно, по-настоящему важных кейсов, где нужно аттачить динамически поведение не вспомнил. Везде только для перехвата событий в сервисе используется, можно просто $obj->on() такое инжектить.

Спасибо.

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.21, 20:29

zelenin писал(а):
2017.04.21, 19:47
так о том и речь, что обсуждаем то, чего нет.
Поразбирался с рефлексией - не получилось ничего.

Но все-таки нашел способ сделать так, чтобы все работало как раньше (с динамическим инжектом и отжектом). Но только со статическими методами и свойствами :)

Код: Выделить всё

<?php

//Упрощенный yii::$app
class Yii
{
    public static $app = [];
}

//Упрощенный yii\base\Trait
trait YiiTrait
{
    function getOwner()
    {
        return Yii::$app['Obj'];
    }
}

//Упрощенный yii\base\Object
class YiiObject
{
    private $traits = [];

    public function attachTrait($trait)
    {
        $this->traits[] = $trait;
    }
    
    public function __call($method, $args)
    {
        foreach($this->traits as $trait) {
            if(method_exists($trait, $method)) {
                return $trait::$method($args);
            }
        }
        
        throw new Exception('Такого метода нет!');
    }
}

//Пользовательский трейт
trait Tr
{
    use YiiTrait;

    function __construct()
    {
        return $this->sum();
    }

    public static function sum()
    {
        return YiiTrait::getOwner()->x + YiiTrait::getOwner()->y;
    }
}

//Пользовательский компонент
class Obj extends YiiObject
{
    public $x;
    public $y;
    
    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
}

//Инит приложения
Yii::$app = [
    'Obj' => new Obj(1, 6),
];

//Если не атачить - вылетет Exception
Yii::$app['Obj']->attachTrait('Tr');

echo Yii::$app['Obj']->sum();

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.21, 20:36

Блин... Теперь пойду ковырять, как Yii узнает, что возвращать в getOwner :D

Аватара пользователя
maleks
Сообщения: 1764
Зарегистрирован: 2012.12.26, 12:56

Re: Как заинжектить трейт в объект

Сообщение maleks » 2017.04.22, 08:36

pistol писал(а):
2017.04.21, 19:56
Подумал еще немного - действительно, по-настоящему важных кейсов, где нужно аттачить динамически поведение не вспомнил. Везде только для перехвата событий в сервисе используется, можно просто $obj->on() такое инжектить.
Если в системе на компонентах есть события, то и должен быть удобный способ навесить сразу набор событий.
Не каждое сидеть и в init() прописывать ->on(), а одним махом. Поведения с этим справляются. Даже пусть эта связь будет статической, все равно это надо. Это в том числе и готовый шаблон Наблюдатель.
Как трейты смогут по нормальному навешивать группы событий на компонент, пока идей нет.

Аватара пользователя
maleks
Сообщения: 1764
Зарегистрирован: 2012.12.26, 12:56

Re: Как заинжектить трейт в объект

Сообщение maleks » 2017.04.22, 10:11

pistol писал(а):
2017.04.21, 20:36
Блин... Теперь пойду ковырять, как Yii узнает, что возвращать в getOwner :D
Бросьте вы это, про "владельца" трейта вам уже выше сказали, а вы все код какой то сочиняете, код получается конечно знатный :) ,но не для ядра yii, может для вашей цмс разве..

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.22, 10:50

maleks писал(а):
2017.04.22, 10:11
pistol писал(а):
2017.04.21, 20:36
Блин... Теперь пойду ковырять, как Yii узнает, что возвращать в getOwner :D
Бросьте вы это, про "владельца" трейта вам уже выше сказали, а вы все код какой то сочиняете, код получается конечно знатный :) ,но не для ядра yii, может для вашей цмс разве..
Ну, я для саморазвития сделал определение owner магией и поздним статическим связыванием. Для пользователя все работает как раньше, за исключением того, что "поведения" теперь должны содержать только статические методы. Такие поведения могут быть приаттачены как трейт (через Use) и динамически через ->attachTrait() уже после инстанцирования класса, результат при этом будет одинаков.

Более того, такие трейты могут быть даже конфигурированы статическими свойствами. И, соответственно, также аттачиться из конфига с настройками:

Код: Выделить всё

'as MyTrait' => [
    'class' => 'common\traits\MyTrait'
    'var1' => 1,
]

Код: Выделить всё

<?php
//Упрощенный yii::$app
class Yii
{
    public static $app = [];
}

//Упрощенный yii\base\Trait
trait YiiTrait
{    
    public static $owner;

    function getOwner()
    {
        if(!$owner = self::$owner) {
            $owner = get_called_class();
        }
        
        return Yii::$app[$owner];
    }
}

//Упрощенный yii\base\Object
class YiiObject
{
    private $traits = [];

    public function attachTrait($trait)
    {  
        $this->traits[] = $trait;
    }
    
    public function __call($method, $args)
    {
        if(isset($this->traits)) {
            foreach($this->traits as $trait) {
                if(method_exists($trait, $method)) {
                    $trait::$owner = get_called_class();
                    $return = $trait::$method($args);
                    $trait::$owner = null;
                    return $return;
                }
            }
        }
        
        throw new Exception('Method don\'t exists');
    }
}

//Пользовательский трейт
trait Tr
{
    public static $owner;
    
    use YiiTrait;

    public static function sum()
    {
        return self::getOwner()->x + self::getOwner()->y;
    }
}

//Пользовательский трейт 2
trait Tr2
{
    use YiiTrait;

    public static function sum()
    {
        return self::getOwner()->x + self::getOwner()->y;
    }
}

//Пользовательский компонент 1
class Obj extends YiiObject
{
    use Tr;
    
    public $x;
    public $y;
    
    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
}

//Пользовательский компонент 2
class Obj2 extends YiiObject
{
    public $x;
    public $y;
    
    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
}

//Инит приложения
Yii::$app = [
    'Obj' => new Obj(1, 6),
    'Obj2' => new Obj2(8, 6),
];

//Если не атачить - вылетет Exception
//Yii::$app['Obj']->attachTrait('Tr'); - это зааттачено через трейт
Yii::$app['Obj2']->attachTrait('Tr2');

echo Yii::$app['Obj']->sum();
echo '<br />';
echo Yii::$app['Obj2']->sum();
echo '<br />';
echo Yii::$app['Obj']->sum();
echo '<br />';
echo Yii::$app['Obj2']->sum();
echo '<br />';
echo Yii::$app['Obj']->sum();

Аватара пользователя
Йож
Сообщения: 571
Зарегистрирован: 2015.08.26, 03:05

Re: Как заинжектить трейт в объект

Сообщение Йож » 2017.04.23, 14:21

Илья, трейт по сути инклуд, как написал Дмитрий Елисеев.

Код: Выделить всё

trait MyTrait
{
    public function sum()
    {
        return "ok";
    }
}

class MyClass {
}

echo (new MyClass)->sum(); //error
Если подключить трейт:

Код: Выделить всё

class MyClass {
    use MyTrait;
}

echo (new MyClass)->sum(); //ok
Зачем там owner определять..
А так Yii 2.2 будет наверно через два года, чего сейчас париться :)
Плюс в тексте написано про traits+events, AccessorTrait, EventTrait etc. В общем механизм будет продуман и задокументирован, останется просто пользоваться :roll:

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.23, 17:33

Йож писал(а):
2017.04.23, 14:21
Илья, трейт по сути инклуд, как написал Дмитрий Елисеев.

Зачем там owner определять..
Да, я понимаю, что это инклуд. Просто стало интересно, возможно ли с трейтами оставить функционал ->attachBehavior(), без owner этого не реализовать. Оказывается, трейты можно юзать без класса, но только статик. функции.
Йож писал(а):
2017.04.23, 14:21
А так Yii 2.2 будет наверно через два года, чего сейчас париться :)
Плюс в тексте написано про traits+events, AccessorTrait, EventTrait etc. В общем механизм будет продуман и задокументирован, останется просто пользоваться :roll:
+, очень интересно, ждем :)

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как заинжектить трейт в объект

Сообщение zelenin » 2017.04.23, 18:02

pistol писал(а):
2017.04.23, 17:33
+, очень интересно, ждем :)
многие умрут к этому времени

Аватара пользователя
Йож
Сообщения: 571
Зарегистрирован: 2015.08.26, 03:05

Re: Как заинжектить трейт в объект

Сообщение Йож » 2017.04.23, 20:11

zelenin писал(а):
2017.04.23, 18:02
многие умрут к этому времени
:D
pistol писал(а):
2017.04.23, 17:33
+, очень интересно, ждем :)
Согласен!

P.S. https://github.com/pistol88/yii2-cart/pull/28
На днях еще до админки yii2-order доберусь основательно, еще чего-нибудь полезное дозакину ;)

Аватара пользователя
SiZE
Сообщения: 2697
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение SiZE » 2017.04.23, 20:24

Ну вы тут и наобсуждали. С одной стороны я рад что люди задаются такими вопросами, с другой стороны удручает, что они не умеют при этом использовать поиск.

https://github.com/yiisoft/yii2/issues/1053
в поиске работы

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.23, 20:29

Йож писал(а):
2017.04.23, 20:11
zelenin писал(а):
2017.04.23, 18:02
многие умрут к этому времени
:D
pistol писал(а):
2017.04.23, 17:33
+, очень интересно, ждем :)
Согласен!

P.S. https://github.com/pistol88/yii2-cart/pull/28
На днях еще до админки yii2-order доберусь основательно, еще чего-нибудь полезное дозакину ;)
Спасибо! Только подожди недельку. https://github.com/dvizh - мы все модули, которые для сайтов, рефакторим тут и скоро выкатим скелетон, в котором очень много всего интересного будет из неопубликованного. Модули из аккаунтов прогеров будут "заморожены" с ссылкой в Ридми на /dvizh.

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.23, 20:30

SiZE писал(а):
2017.04.23, 20:24
Ну вы тут и наобсуждали. С одной стороны я рад что люди задаются такими вопросами, с другой стороны удручает, что они не умеют при этом использовать поиск.

https://github.com/yiisoft/yii2/issues/1053
Ух-ты, спасибо!)

Аватара пользователя
pistol
Сообщения: 216
Зарегистрирован: 2014.07.12, 15:18
Откуда: Курган
Контактная информация:

Re: Как заинжектить трейт в объект

Сообщение pistol » 2017.04.23, 20:42

SiZE писал(а):
2017.04.23, 20:24
Ну вы тут и наобсуждали. С одной стороны я рад что люди задаются такими вопросами, с другой стороны удручает, что они не умеют при этом использовать поиск.

https://github.com/yiisoft/yii2/issues/1053
Правда, по всей видимости, инфа устарела. В этом топике в 2013 было решено оставить поведения.

Ответить