public function toSetter(MetaClass $class, MetaClassProperty $property, MetaClassProperty $holder = null)
    {
        $name = $property->getName();
        $methodName = 'set' . ucfirst($name);
        if ($holder) {
            return <<<EOT

/**
 * @return {$holder->getClass()->getName()}
**/
public function {$methodName}(\${$name})
{
\t\$this->{$holder->getName()}->{$methodName}(\${$name});

\treturn \$this;
}

EOT;
        } else {
            return <<<EOT

/**
 * @return {$class->getName()}
**/
public function {$methodName}(\${$name})
{
\t\$this->{$name} = \${$name};

\treturn \$this;
}

EOT;
        }
        Assert::isUnreachable();
    }
    public function toSetter(MetaClass $class, MetaClassProperty $property, MetaClassProperty $holder = null)
    {
        $name = $property->getName();
        $methodName = 'set' . ucfirst($name);
        if ($holder) {
            return <<<EOT

/**
 * @return {$holder->getClass()->getName()}
**/
public function {$methodName}(\${$name})
{
\t\$this->{$holder->getName()}->{$methodName}(\${$name});

\treturn \$this;
}

EOT;
        } else {
            if ($property->isRequired()) {
                $method = <<<EOT

/**
 * @return {$class->getName()}
**/
public function {$methodName}(\${$name} = false)
{
\t\$this->{$name} = (\${$name} === true);

\treturn \$this;
}

EOT;
            } else {
                $method = <<<EOT

/**
 * @return {$class->getName()}
**/
public function {$methodName}(\${$name} = null)
{
\tAssert::isTernaryBase(\${$name});
\t
\t\$this->{$name} = \${$name};

\treturn \$this;
}

EOT;
            }
        }
        return $method;
    }
    public static function buildContainer(MetaClass $class, MetaClassProperty $holder)
    {
        $out = self::getHead();
        $containerName = $class->getName() . ucfirst($holder->getName()) . 'DAO';
        $out .= 'final class ' . $containerName . ' extends ' . $holder->getRelation()->toString() . 'Linked' . "\n{\n";
        $className = $class->getName();
        $propertyName = strtolower($className[0]) . substr($className, 1);
        $remoteColumnName = $holder->getType()->getClass()->getTableName();
        $out .= <<<EOT
public function __construct({$className} \${$propertyName}, \$lazy = false)
{
\tparent::__construct(
\t\t\${$propertyName},
\t\t{$holder->getType()->getClassName()}::dao(),
\t\t\$lazy
\t);
}

/**
 * @return {$containerName}
**/
public static function create({$className} \${$propertyName}, \$lazy = false)
{
\treturn new self(\${$propertyName}, \$lazy);
}

EOT;
        if ($holder->getRelation()->getId() == MetaRelation::MANY_TO_MANY) {
            $out .= <<<EOT

public function getHelperTable()
{
\treturn '{$class->getTableName()}_{$remoteColumnName}';
}

public function getChildIdField()
{
\treturn '{$remoteColumnName}_id';
}

EOT;
        }
        $out .= <<<EOT

public function getParentIdField()
{
\treturn '{$class->getTableName()}_id';
}

EOT;
        $out .= "}\n";
        $out .= self::getHeel();
        return $out;
    }
 private static function doPropertyBuild(MetaClass $class, MetaClassProperty $property, $isNamed)
 {
     if ($parentProperty = $class->isRedefinedProperty($property->getName())) {
         // check wheter property fetch strategy becomes lazy
         if ($parentProperty->getFetchStrategyId() != $property->getFetchStrategyId() && $property->getFetchStrategyId() === FetchStrategy::LAZY) {
             return true;
         }
         return false;
     }
     if ($isNamed && $property->getName() == 'name') {
         return false;
     }
     if ($property->getName() == 'id' && !$property->getClass()->getParent()) {
         return false;
     }
     // do not redefine parent's properties
     if ($property->getClass()->getParent() && array_key_exists($property->getName(), $property->getClass()->getAllParentsProperties())) {
         return false;
     }
     return true;
 }
 public function equals(MetaClassProperty $property)
 {
     return $property->getName() == $this->getName() && $property->getColumnName() == $this->getColumnName() && $property->getType() == $this->getType() && $property->getSize() == $this->getSize() && $property->getRelation() == $this->getRelation() && $property->isRequired() == $this->isRequired() && $property->isIdentifier() == $this->isIdentifier();
 }
 private function checkRecursion(MetaClassProperty $property, MetaClass $holder, $paths = array())
 {
     Assert::isTrue($property->getRelationId() == MetaRelation::ONE_TO_ONE);
     if ($property->getFetchStrategy() && $property->getFetchStrategy()->getId() != FetchStrategy::JOIN) {
         return false;
     }
     $remote = $property->getType()->getClass();
     if (isset($paths[$holder->getName()][$remote->getName()])) {
         return true;
     } else {
         $paths[$holder->getName()][$remote->getName()] = true;
         foreach ($remote->getProperties() as $remoteProperty) {
             if ($remoteProperty->getRelationId() == MetaRelation::ONE_TO_ONE) {
                 if ($this->checkRecursion($remoteProperty, $holder, $paths)) {
                     $remoteProperty->setFetchStrategy(FetchStrategy::cascade());
                 }
             }
         }
     }
     return false;
 }
    public function toDropper(MetaClass $class, MetaClassProperty $property, MetaClassProperty $holder = null)
    {
        if ($property->getRelationId() == MetaRelation::ONE_TO_MANY || $property->getRelationId() == MetaRelation::MANY_TO_MANY) {
            // we don't need dropper in such cases
            return null;
        }
        $name = $property->getName();
        $methodName = 'drop' . ucfirst($name);
        if ($holder) {
            $method = <<<EOT

/**
 * @return {$holder->getClass()->getName()}
**/
public function {$methodName}()
{
\t\$this->{$holder->getName()}->{$methodName}();

\treturn \$this;
}

EOT;
        } else {
            if ($property->getFetchStrategyId() == FetchStrategy::LAZY) {
                $method = <<<EOT

/**
 * @return {$class->getName()}
**/
public function {$methodName}()
{
\t\$this->{$name} = null;
\t\$this->{$name}Id = null;

\treturn \$this;
}

EOT;
            } else {
                $method = <<<EOT

/**
 * @return {$class->getName()}
**/
public function {$methodName}()
{
\t\$this->{$name} = null;

\treturn \$this;
}

EOT;
            }
        }
        return $method;
    }
 /**
  * @return MetaClass
  **/
 public function addProperty(MetaClassProperty $property)
 {
     $name = $property->getName();
     if (!isset($this->properties[$name])) {
         $this->properties[$name] = $property;
     } else {
         throw new WrongArgumentException("property '{$name}' already exist");
     }
     if ($property->isIdentifier()) {
         $this->identifier = $property;
     }
     return $this;
 }