<commit_before><?php

/*
 * This file is part of the CRUDlex package.
 *
 * (c) <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CRUDlex;

use Doctrine\DBAL\Query\QueryBuilder;
use CRUDlex\CRUDEntity;
use CRUDlex\CRUDData;
use CRUDlex\CRUDFileProcessorInterface;

/**
 * MySQL CRUDData implementation using a given Doctrine DBAL instance.
 */
class CRUDMySQLData extends CRUDData {

    /**
     * Holds the Doctrine DBAL instance.
     */
    protected $db;

    /**
     * Sets the values and parameters of the upcoming given query according
     * to the entity.
     *
     * @param CRUDEntity $entity
     * the entity with its fields and values
     * @param QueryBuilder $queryBuilder
     * the upcoming query
     * @param boolean $setValue
     * whether to use QueryBuilder::setValue (true) or QueryBuilder::set (false)
     */
    protected function setValuesAndParameters(CRUDEntity $entity, QueryBuilder $queryBuilder, $setValue) {
        $formFields = $this->definition->getEditableFieldNames();
        $count = count($formFields);
        for ($i = 0; $i < $count; ++$i) {
            $value = $entity->get($formFields[$i]);
            $type = $this->definition->getType($formFields[$i]);
            if ($type == 'bool') {
                $value = $value ? 1 : 0;
            }
            if ($type == 'date' || $type == 'datetime' || $type == 'reference') {
                $value = $value == '' ? null : $value;
            }
            if ($setValue) {
                $queryBuilder->setValue('`'.$formFields[$i].'`', '?');
            } else {
                $queryBuilder->set('`'.$formFields[$i].'`', '?');
            }
            $queryBuilder->setParameter($i, $value);
        }
    }

    /**
     * Performs the cascading children deletion.
     *
     * @param integer $id
     * the current entities id
     * @param boolean $deleteCascade
     * whether to delete children and subchildren
     */
    protected function deleteChildren($id, $deleteCascade) {
        foreach ($this->definition->getChildren() as $childArray) {
            $childData = $this->definition->getServiceProvider()->getData($childArray[2]);
            $children = $childData->listEntries(array($childArray[1] => $id));
            foreach ($children as $child) {
                $childData->doDelete($child, $deleteCascade);
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function doDelete(CRUDEntity $entity, $deleteCascade) {
        $result = $this->executeEvents($entity, 'before', 'delete');
        if (!$result) {
            return static::DELETION_FAILED_EVENT;
        }
        $id = $entity->get('id');
        if ($deleteCascade) {
            $this->deleteChildren($id, $deleteCascade);
        } else {
            foreach ($this->definition->getChildren() as $child) {
                $queryBuilder = $this->db->createQueryBuilder();
                $queryBuilder
                    ->select('COUNT(id)')
                    ->from($child[0], $child[0])
                    ->where($child[1].' = ?')
                    ->andWhere('deleted_at IS NULL')
                    ->setParameter(0, $id);
                $queryResult = $queryBuilder->execute();
                $result = $queryResult->fetch(\PDO::FETCH_NUM);
                if ($result[0] > 0) {
                    return static::DELETION_FAILED_STILL_REFERENCED;
                }
            }
        }

        $query = $this->db->createQueryBuilder();
        $query
            ->update($this->definition->getTable())
            ->set('deleted_at', 'NOW()')
            ->where('id = ?')
            ->setParameter(0, $id);

        $query->execute();
        $this->executeEvents($entity, 'after', 'delete');
        return static::DELETION_SUCCESS;
    }

    /**
     * Adds sorting parameters to the query.
     *
     * @param QueryBuilder $queryBuilder
     * the query
     * @param $filter
     * the filter all resulting entities must fulfill, the keys as field names
     * @param $filterOperators
     * the operators of the filter like "=" defining the full condition of the field
     */
    protected function addFilter(QueryBuilder $queryBuilder, array $filter, array $filterOperators) {
        $i = 0;
        foreach ($filter as $field => $value) {
            if ($value === null) {
                $queryBuilder->andWhere('`'.$field.'` IS NULL');
            } else {
                $operator = array_key_exists($field, $filterOperators) ? $filterOperators[$field] : '=';<commit_msg>moved the check for children out of CRUDMySQLData::doDelete()<commit_after><?php

/*
 * This file is part of the CRUDlex package.
 *
 * (c) <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CRUDlex;

use Doctrine\DBAL\Query\QueryBuilder;
use CRUDlex\CRUDEntity;
use CRUDlex\CRUDData;
use CRUDlex\CRUDFileProcessorInterface;

/**
 * MySQL CRUDData implementation using a given Doctrine DBAL instance.
 */
class CRUDMySQLData extends CRUDData {

    /**
     * Holds the Doctrine DBAL instance.
     */
    protected $db;

    /**
     * Sets the values and parameters of the upcoming given query according
     * to the entity.
     *
     * @param CRUDEntity $entity
     * the entity with its fields and values
     * @param QueryBuilder $queryBuilder
     * the upcoming query
     * @param boolean $setValue
     * whether to use QueryBuilder::setValue (true) or QueryBuilder::set (false)
     */
    protected function setValuesAndParameters(CRUDEntity $entity, QueryBuilder $queryBuilder, $setValue) {
        $formFields = $this->definition->getEditableFieldNames();
        $count = count($formFields);
        for ($i = 0; $i < $count; ++$i) {
            $value = $entity->get($formFields[$i]);
            $type = $this->definition->getType($formFields[$i]);
            if ($type == 'bool') {
                $value = $value ? 1 : 0;
            }
            if ($type == 'date' || $type == 'datetime' || $type == 'reference') {
                $value = $value == '' ? null : $value;
            }
            if ($setValue) {
                $queryBuilder->setValue('`'.$formFields[$i].'`', '?');
            } else {
                $queryBuilder->set('`'.$formFields[$i].'`', '?');
            }
            $queryBuilder->setParameter($i, $value);
        }
    }

    /**
     * Performs the cascading children deletion.
     *
     * @param integer $id
     * the current entities id
     * @param boolean $deleteCascade
     * whether to delete children and subchildren
     */
    protected function deleteChildren($id, $deleteCascade) {
        foreach ($this->definition->getChildren() as $childArray) {
            $childData = $this->definition->getServiceProvider()->getData($childArray[2]);
            $children = $childData->listEntries(array($childArray[1] => $id));
            foreach ($children as $child) {
                $childData->doDelete($child, $deleteCascade);
            }
        }
    }

    /**
     * Checks whether the by id given entity still has children referencing it.
     *
     * @param integer $id
     * the current entities id
     *
     * @return boolean
     * true if the entity still has children
     */
    protected function hasChildren($id) {
        foreach ($this->definition->getChildren() as $child) {
            $queryBuilder = $this->db->createQueryBuilder();
            $queryBuilder
                ->select('COUNT(id)')
                ->from($child[0], $child[0])
                ->where($child[1].' = ?')
                ->andWhere('deleted_at IS NULL')
                ->setParameter(0, $id);
            $queryResult = $queryBuilder->execute();
            $result = $queryResult->fetch(\PDO::FETCH_NUM);
            if ($result[0] > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * {@inheritdoc}
     */
    protected function doDelete(CRUDEntity $entity, $deleteCascade) {
        $result = $this->executeEvents($entity, 'before', 'delete');
        if (!$result) {
            return static::DELETION_FAILED_EVENT;
        }
        $id = $entity->get('id');
        if ($deleteCascade) {
            $this->deleteChildren($id, $deleteCascade);
        } else if ($this->hasChildren($id)) {
            return static::DELETION_FAILED_STILL_REFERENCED;
        }

        $query = $this->db->createQueryBuilder();
        $query
            ->update($this->definition->getTable())
            ->set('deleted_at', 'NOW()')
            ->where('id = ?')
            ->setParameter(0, $id);

        $query->execute();
        $this->executeEvents($entity, 'after', 'delete');
        return static::DELETION_SUCCESS;
    }

    /**
     * Adds sorting parameters to the query.
     *
     * @param QueryBuilder $queryBuilder
     * the query
     * @param $filter
     * the filter all resulting entities must fulfill, the keys as field names
     * @param $filterOperators
     * the operators of the filter like "=" defining the full condition of the field
     */
    protected function addFilter(QueryBuilder $queryBuilder, array $filter, array $filterOperators) {
        $i = 0;
        foreach ($filter as $field => $value) {
            if ($value === null) {
                $queryBuilder->andWhere('`'.$field.'` IS NULL');
            } else {
                $operator = array_key_exists($field, $filterOperators) ? $filterOperators[$field] : '=';
{'fraction_non_alphanumeric': 0.13967695174984468, 'fraction_numerical': 0.002692068751294264, 'mean_word_length': 2.1127940702545924, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 96, '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': '2620267', 'n_tokens_mistral': 2713, 'n_tokens_neox': 2673, 'n_words': 674}