<commit_before><?php
namespace ShadowTranslate\Model\Behavior;

use ArrayObject;
use Cake\Database\Expression\FieldInterface;
use Cake\Event\Event;
use Cake\ORM\Behavior;
use Cake\ORM\Behavior\TranslateBehavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Utility\Inflector;

/**
 * ShadowTranslate behavior
 */
class ShadowTranslateBehavior extends TranslateBehavior
{
    /**
     * Constructor
     *
     * @param \Cake\ORM\Table $table Table instance
     * @param array $config Configuration
     */
    public function __construct(Table $table, array $config = [])
    {
        if (isset($config['referenceName'])) {
            $referenceName = $config['referenceName'];
            $dbTable = Inflector::underscore($referenceName);
        } else {
            $referenceName = $table->alias();
            $dbTable = $table->table();
        }

        $config += [
            'mainTableAlias' => $table->alias(),
            'translationTable' => $dbTable . '_translations',
            'translationTableAlias' => $referenceName . 'Translations'
        ];

        parent::__construct($table, $config);
    }

    /**
     * Create a hasMany association for all records
     *
     * Don't create a hasOne association here as the join conditions are modified
     * in before find - so create/modify it there
     *
     * @param array $fields - ignored
     * @param string $table - ignored
     * @param string $fieldConditions - ignored
     * @param string $strategy the strategy used in the _i18n association
     *
     * @return void
     */
    public function setupFieldAssociations($fields, $table, $fieldConditions, $strategy)
    {
        $targetAlias = $this->_translationTable->alias();
        $this->_table->hasMany($targetAlias, [
            'foreignKey' => 'id',
            'strategy' => $strategy,
            'propertyName' => '_i18n',
            'dependent' => true
        ]);
    }

    /**
     * Callback method that listens to the `beforeFind` event in the bound
     * table. It modifies the passed query by eager loading the translated fields
     * and adding a formatter to copy the values into the main table records.
     *
     * @param \Cake\Event\Event $event The beforeFind event that was fired.
     * @param \Cake\ORM\Query $query Query
     * @param \ArrayObject $options The options for the query
     * @return void
     */
    public function beforeFind(Event $event, Query $query, $options)
    {
        $locale = $this->locale();

        if ($locale === $this->config('defaultLocale')) {
            return;
        }

        $config = $this->config();

        if (isset($options['filterByCurrentLocale'])) {
            $joinType = $options['filterByCurrentLocale'] ? 'INNER' : 'LEFT';
        } else {
            $joinType = $config['onlyTranslated'] ? 'INNER' : 'LEFT';
        }

        $this->_table->hasOne($config['translationTableAlias'], [
            'foreignKey' => ['id'],
            'joinType' => $joinType,
            'propertyName' => 'translation',
            'conditions' => [
                $config['translationTableAlias'] . '.locale' => $locale,
            ],
        ]);
        $query->contain([$config['translationTableAlias']]);

        $this->_addFieldsToQuery($query, $config);
        $this->_iterateClause($query, 'order', $config);
        $this->_traverseClause($query, 'where', $config);

        $query->formatResults(function ($results) use ($locale) {
            return $this->_rowMapper($results, $locale);
        }, $query::PREPEND);
    }

    /**
     * Add translation fields to query
     *
     * If the query is using autofields (directly or implicitly) add the
     * main table's fields to the query first.
     *
     * Only add translations for fields that are in the main table, always
     * add the locale field though.
     *
     * @param \Cake\ORM\Query $query the query to check
     * @param array $config the config to use for adding fields
     * @return void
     */
    protected function _addFieldsToQuery(Query $query, array $config)
    {
        $select = $query->clause('select');

        if (!$select) {
            // rely on auto fields, no need to specify fields
            return;
        }

        $alias = $config['mainTableAlias'];
        foreach ($this->_translationFields() as $field) {
            if (
                in_array($field, $select, true) ||
                in_array("$alias.$field", $select, true)
            ) {
                $query->select($query->aliasField($field, $config['translationTableAlias']));
            }
        }
        $query->select($query->aliasField('locale', $config['translationTableAlias']));
    }

    /**
     * Iterate over a clause to alias fields
     *
     * The objective here is to transparently prevent ambiguous field errors by
     * prefixing fields with the appropriate table alias. This method currently
     * expects to receive an order clause only.
     *
     * @param \Cake\ORM\Query $query the query to check
     * @param string $name The clause name
     * @param array $config the config to use for adding fields
     * @return void
     */
    protected function _iterateClause(Query $query, $name = '', $config = [])
    {
        $clause = $query->clause($name);
        if (!$clause || !$clause->count()) {
            return;
        }

        $alias = $config['translationTableAlias'];
        $fields = $this->_translationFields();
        $mainTableAlias = $config['mainTableAlias'];<commit_msg>And don't add in the locale field unnecessarily<commit_after><?php
namespace ShadowTranslate\Model\Behavior;

use ArrayObject;
use Cake\Database\Expression\FieldInterface;
use Cake\Event\Event;
use Cake\ORM\Behavior;
use Cake\ORM\Behavior\TranslateBehavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Utility\Inflector;

/**
 * ShadowTranslate behavior
 */
class ShadowTranslateBehavior extends TranslateBehavior
{
    /**
     * Constructor
     *
     * @param \Cake\ORM\Table $table Table instance
     * @param array $config Configuration
     */
    public function __construct(Table $table, array $config = [])
    {
        if (isset($config['referenceName'])) {
            $referenceName = $config['referenceName'];
            $dbTable = Inflector::underscore($referenceName);
        } else {
            $referenceName = $table->alias();
            $dbTable = $table->table();
        }

        $config += [
            'mainTableAlias' => $table->alias(),
            'translationTable' => $dbTable . '_translations',
            'translationTableAlias' => $referenceName . 'Translations'
        ];

        parent::__construct($table, $config);
    }

    /**
     * Create a hasMany association for all records
     *
     * Don't create a hasOne association here as the join conditions are modified
     * in before find - so create/modify it there
     *
     * @param array $fields - ignored
     * @param string $table - ignored
     * @param string $fieldConditions - ignored
     * @param string $strategy the strategy used in the _i18n association
     *
     * @return void
     */
    public function setupFieldAssociations($fields, $table, $fieldConditions, $strategy)
    {
        $targetAlias = $this->_translationTable->alias();
        $this->_table->hasMany($targetAlias, [
            'foreignKey' => 'id',
            'strategy' => $strategy,
            'propertyName' => '_i18n',
            'dependent' => true
        ]);
    }

    /**
     * Callback method that listens to the `beforeFind` event in the bound
     * table. It modifies the passed query by eager loading the translated fields
     * and adding a formatter to copy the values into the main table records.
     *
     * @param \Cake\Event\Event $event The beforeFind event that was fired.
     * @param \Cake\ORM\Query $query Query
     * @param \ArrayObject $options The options for the query
     * @return void
     */
    public function beforeFind(Event $event, Query $query, $options)
    {
        $locale = $this->locale();

        if ($locale === $this->config('defaultLocale')) {
            return;
        }

        $config = $this->config();

        if (isset($options['filterByCurrentLocale'])) {
            $joinType = $options['filterByCurrentLocale'] ? 'INNER' : 'LEFT';
        } else {
            $joinType = $config['onlyTranslated'] ? 'INNER' : 'LEFT';
        }

        $this->_table->hasOne($config['translationTableAlias'], [
            'foreignKey' => ['id'],
            'joinType' => $joinType,
            'propertyName' => 'translation',
            'conditions' => [
                $config['translationTableAlias'] . '.locale' => $locale,
            ],
        ]);
        $query->contain([$config['translationTableAlias']]);

        $this->_addFieldsToQuery($query, $config);
        $this->_iterateClause($query, 'order', $config);
        $this->_traverseClause($query, 'where', $config);

        $query->formatResults(function ($results) use ($locale) {
            return $this->_rowMapper($results, $locale);
        }, $query::PREPEND);
    }

    /**
     * Add translation fields to query
     *
     * If the query is using autofields (directly or implicitly) add the
     * main table's fields to the query first.
     *
     * Only add translations for fields that are in the main table, always
     * add the locale field though.
     *
     * @param \Cake\ORM\Query $query the query to check
     * @param array $config the config to use for adding fields
     * @return void
     */
    protected function _addFieldsToQuery(Query $query, array $config)
    {
        $select = $query->clause('select');

        if (!$select) {
            // rely on auto fields, no need to specify fields
            return;
        }

        $alias = $config['mainTableAlias'];
        $fieldAdded = false;
        foreach ($this->_translationFields() as $field) {
            if (
                in_array($field, $select, true) ||
                in_array("$alias.$field", $select, true)
            ) {
                $fieldAdded = true;
                $query->select($query->aliasField($field, $config['translationTableAlias']));
            }
        }

        if ($fieldAdded) {
            $query->select($query->aliasField('locale', $config['translationTableAlias']));
        }
    }

    /**
     * Iterate over a clause to alias fields
     *
     * The objective here is to transparently prevent ambiguous field errors by
     * prefixing fields with the appropriate table alias. This method currently
     * expects to receive an order clause only.
     *
     * @param \Cake\ORM\Query $query the query to check
     * @param string $name The clause name
     * @param array $config the config to use for adding fields
     * @return void
     */
    protected function _iterateClause(Query $query, $name = '', $config = [])
    {
        $clause = $query->clause($name);
        if (!$clause || !$clause->count()) {
            return;
        }

        $alias = $config['translationTableAlias'];
        $fields = $this->_translationFields();
        $mainTableAlias = $config['mainTableAlias'];
{'fraction_non_alphanumeric': 0.12731297034085878, 'fraction_numerical': 0.0007082779991146526, 'mean_word_length': 2.3116388155965994, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3392543', 'n_tokens_mistral': 3091, 'n_tokens_neox': 3027, 'n_words': 854}