<?php

namespace Doctrine\Tests\ORM\Functional\Ticket;

require_once __DIR__ . '/../../../TestInit.php';

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;


/**
 * @group DDC-2012
 */
class DDC2012Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
    protected function setUp()
    {
        parent::setUp();

        Type::addType(DDC2012TsVectorType::MYTYPE, __NAMESPACE__ . '\DDC2012TsVectorType');

        $this->_schemaTool->createSchema(array(
            $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2012Item'),
            $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2012ItemPerson'),
        ));
    }

    public function testIssue()
    {
        DDC2012TsVectorType::$calls = array();

        $item       = new DDC2012ItemPerson;
        $item->tsv  = new DDC2012TsVector('bar');

        $this->_em->persist($item);
        $this->_em->flush();
        $this->_em->clear();

        $item = $this->_em->getRepository(__NAMESPACE__ . '\DDC2012Item')->findOneBy(array(
            'tsv' => new DDC2012TsVector('bar')
        ));

        $this->assertInstanceOf(__NAMESPACE__ . '\DDC2012Item', $item);
        $this->assertInstanceOf(__NAMESPACE__ . '\DDC2012TsVector', $item->tsv);

        $this->assertArrayHasKey('convertToDatabaseValueSQL', DDC2012TsVectorType::$calls);
        $this->assertArrayHasKey('convertToDatabaseValue', DDC2012TsVectorType::$calls);
        $this->assertArrayHasKey('convertToPHPValue', DDC2012TsVectorType::$calls);

        $this->assertCount(1, DDC2012TsVectorType::$calls['convertToDatabaseValueSQL']);
        $this->assertCount(2, DDC2012TsVectorType::$calls['convertToDatabaseValue']);
        $this->assertCount(1, DDC2012TsVectorType::$calls['convertToPHPValue']);

        $expectedSQL   = 'SELECT t0.id AS id1, t0.tsv AS tsv2, t0.type_id FROM ddc2010_item t0 LEFT JOIN ddc2010_item_person t3 ON t0.id = t3.id WHERE t0.tsv = UPPER(?) LIMIT 1';
        $expectedTypes = array(DDC2012TsVectorType::MYTYPE);

        $this->assertEquals($expectedSQL, $this->_sqlLoggerStack->queries[7]['sql']);
        $this->assertEquals($expectedTypes, $this->_sqlLoggerStack->queries[7]['types']);
    }
}

/**
 * @Table(name="ddc2010_item")
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="type_id", type="smallint")
 * @DiscriminatorMap({1 = "DDC2012ItemPerson"})
 */
class DDC2012Item
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(type="integer") 
     */
    public $id;

    /**
     * @Column(name="tsv", type="tsvector", nullable=true)
     */
    public $tsv;
}

/**
 * @Table(name="ddc2010_item_person")
 * @Entity
 */
class DDC2012ItemPerson extends DDC2012Item
{

}

class DDC2012TsVectorType extends Type
{
    const MYTYPE = 'tsvector';

    public static $calls = array();

    /**
     * {@inheritdoc}
     */
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        return $platform->getBlobTypeDeclarationSQL($fieldDeclaration);
    }

    /**
     * {@inheritdoc}
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        self::$calls[__FUNCTION__][] = array(
            'value'     => $value,
            'platform'  => $platform,
        );

        return strtoupper($value);
    }

    /**
     * {@inheritdoc}
     */
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        self::$calls[__FUNCTION__][] = array(
            'value'     => $value,
            'platform'  => $platform,
        );

        return new DDC2012TsVector($value);
    }

    /**
     * {@inheritdoc}
     */
    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
    {
        self::$calls[__FUNCTION__][] = array(
            'sqlExpr'   => $sqlExpr,
            'platform'  => $platform,
        );

        return $platform->getUpperExpression($sqlExpr);
    }

    /**
     * {@inheritdoc}
     */
    public function canRequireSQLConversion()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return self::MYTYPE;
    }
}

class DDC2012TsVector
{
    private $data;

    public function __construct($data)
    {
        $this->data = strtolower($data);
    }

    public function __toString()
    {
        return $this->data;
    }
}