<commit_before><?php
/**
 * Webiny Framework (http://www.webiny.com/framework)
 *
 * @copyright Copyright Webiny LTD
 */

namespace Webiny\Component\Entity\Attribute;

use Traversable;
use Webiny\Component\Entity\EntityAbstract;
use Webiny\Component\Entity\EntityCollection;
use Webiny\Component\StdLib\StdLibTrait;


/**
 * One2Many attribute
 * @package Webiny\Component\Entity\AttributeType
 */
class One2ManyAttribute extends CollectionAttributeAbstract
{
    use StdLibTrait;

    protected $relatedAttribute = null;
    protected $filter = [];
    protected $sorter = [];
    protected $onDelete = 'cascade';

    /**
     * @var null|\Webiny\Component\Entity\EntityAbstract
     */
    protected $entity = null;

    /**
     * @param string         $attribute
     * @param EntityAbstract $entity
     * @param string         $relatedAttribute
     */
    public function __construct($attribute, EntityAbstract $entity, $relatedAttribute)
    {
        $this->relatedAttribute = $relatedAttribute;
        parent::__construct($attribute, $entity);
    }

    /**
     * Filter returned result set
     *
     * @param array $filter
     *
     * @return $this
     */
    public function setFilter(array $filter)
    {
        $this->filter = $filter;

        return $this;
    }

    /**
     * Sort returned result set
     *
     * @param array|string $sorter Ex: ['-order', '+createdOn'] or '-order,+createdOn'
     *
     * @return $this
     */
    public function setSorter($sorter)
    {
        $this->sorter = $this->parseSorter($sorter);

        return $this;
    }

    /**
     * Get action to perform when parent entity is being deleted.
     *
     * @return string
     */
    public function getOnDelete()
    {
        return $this->onDelete;
    }

    /**
     * Set action to perform when parent entity is being deleted.
     *
     * @param string $action cascade|restrict Default value is 'cascade'
     *
     * @return $this
     */
    public function setOnDelete($action = 'cascade')
    {
        if ($action != 'cascade' && $action != 'restrict') {
            $action = 'cascade';
        }

        $this->onDelete = $action;

        return $this;
    }

    /**
     * Get attribute that defines a foreign key
     */
    public function getRelatedAttribute()
    {
        return $this->relatedAttribute;
    }

    public function setValue($value = null, $fromDb = false)
    {
        if(!$this->canAssign()){
            return $this;
        }

        $this->value = $value;

        return $this;
    }

    /**
     * Set or get attribute value
     *
     * @return bool|null|\Webiny\Component\Entity\EntityAbstract
     */
    public function getValue()
    {
        if ($this->isNull($this->value)) {
            $query = [
                $this->relatedAttribute => $this->entity->getId()->getValue()
            ];

            $query = array_merge($query, $this->filter);

            $callable = [
                $this->entityClass,
                'find'
            ];
            $this->value = call_user_func_array($callable, [$query, $this->sorter]);
        }

        return $this->value;
    }

    private function parseSorter($fields){
        $sorters = [];

        if(is_string($fields)){
            $fields = explode(',', $fields);
        }

        foreach($fields as $sort){
            $sortField = $sort;
            $sortDirection = 1;

            $sortDirectionSign = substr($sort, 0, 1);
            if ($sortDirectionSign == '+' || $sortDirectionSign == '-') {
                $sortField = substr($sort, 1);
                $sortDirection = $sortDirectionSign == '+' ? 1 : -1;
            }

            $sorters[$sortField] = $sortDirection;
        }

        return $sorters;
    }
}<commit_msg>Fixed One2Many empty ID data loading<commit_after><?php
/**
 * Webiny Framework (http://www.webiny.com/framework)
 *
 * @copyright Copyright Webiny LTD
 */

namespace Webiny\Component\Entity\Attribute;

use Traversable;
use Webiny\Component\Entity\EntityAbstract;
use Webiny\Component\Entity\EntityCollection;
use Webiny\Component\StdLib\StdLibTrait;


/**
 * One2Many attribute
 * @package Webiny\Component\Entity\AttributeType
 */
class One2ManyAttribute extends CollectionAttributeAbstract
{
    use StdLibTrait;

    protected $relatedAttribute = null;
    protected $filter = [];
    protected $sorter = [];
    protected $onDelete = 'cascade';

    /**
     * @var null|\Webiny\Component\Entity\EntityAbstract
     */
    protected $entity = null;

    /**
     * @param string         $attribute
     * @param EntityAbstract $entity
     * @param string         $relatedAttribute
     */
    public function __construct($attribute, EntityAbstract $entity, $relatedAttribute)
    {
        $this->relatedAttribute = $relatedAttribute;
        parent::__construct($attribute, $entity);
    }

    /**
     * Filter returned result set
     *
     * @param array $filter
     *
     * @return $this
     */
    public function setFilter(array $filter)
    {
        $this->filter = $filter;

        return $this;
    }

    /**
     * Sort returned result set
     *
     * @param array|string $sorter Ex: ['-order', '+createdOn'] or '-order,+createdOn'
     *
     * @return $this
     */
    public function setSorter($sorter)
    {
        $this->sorter = $this->parseSorter($sorter);

        return $this;
    }

    /**
     * Get action to perform when parent entity is being deleted.
     *
     * @return string
     */
    public function getOnDelete()
    {
        return $this->onDelete;
    }

    /**
     * Set action to perform when parent entity is being deleted.
     *
     * @param string $action cascade|restrict Default value is 'cascade'
     *
     * @return $this
     */
    public function setOnDelete($action = 'cascade')
    {
        if ($action != 'cascade' && $action != 'restrict') {
            $action = 'cascade';
        }

        $this->onDelete = $action;

        return $this;
    }

    /**
     * Get attribute that defines a foreign key
     */
    public function getRelatedAttribute()
    {
        return $this->relatedAttribute;
    }

    public function setValue($value = null, $fromDb = false)
    {
        if(!$this->canAssign()){
            return $this;
        }

        $this->value = $value;

        return $this;
    }

    /**
     * Set or get attribute value
     *
     * @return bool|null|\Webiny\Component\Entity\EntityAbstract
     */
    public function getValue()
    {
        if ($this->isNull($this->value)) {
            $entityId = $this->entity->id;
            $entityId = empty($entityId) ? '__webiny_dummy_id__' : $entityId;
            $query = [
                $this->relatedAttribute => $entityId
            ];

            $query = array_merge($query, $this->filter);

            $callable = [
                $this->entityClass,
                'find'
            ];
            $this->value = call_user_func_array($callable, [$query, $this->sorter]);
        }

        return $this->value;
    }

    private function parseSorter($fields){
        $sorters = [];

        if(is_string($fields)){
            $fields = explode(',', $fields);
        }

        foreach($fields as $sort){
            $sortField = $sort;
            $sortDirection = 1;

            $sortDirectionSign = substr($sort, 0, 1);
            if ($sortDirectionSign == '+' || $sortDirectionSign == '-') {
                $sortField = substr($sort, 1);
                $sortDirection = $sortDirectionSign == '+' ? 1 : -1;
            }

            $sorters[$sortField] = $sortDirection;
        }

        return $sorters;
    }
}
{'fraction_non_alphanumeric': 0.13155497722836695, 'fraction_numerical': 0.0022121014964216006, 'mean_word_length': 1.9641342074816814, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1370075', 'n_tokens_mistral': 2234, 'n_tokens_neox': 2170, 'n_words': 485}