Merged in bugfix/PMCORE-496 (pull request #7204)

PMCORE-496 Review why the command ./gulliver has some problems in the version 3.x

Approved-by: Julio Cesar Laura Avendaño <contact@julio-laura.com>
This commit is contained in:
Roly
2020-01-17 14:06:49 +00:00
committed by Julio Cesar Laura Avendaño
16 changed files with 518 additions and 465 deletions

View File

@@ -190,7 +190,11 @@ CREATE TABLE ".$this->quoteIdentifier($table->getName())."
foreach ($table->getIndices() as $index ) {
$vendor = $index->getVendorSpecificInfo();
$lines[] .= (($vendor && $vendor['Index_type'] == 'FULLTEXT') ? 'FULLTEXT ' : '') . "KEY " . $this->quoteIdentifier($index->getName()) . "(" . $this->getIndexColumnList($index) . ")";
$word = "KEY ";
if (!empty($index->getIndexType())) {
$word = $index->getIndexType() . " ";
}
$lines[] .= (($vendor && $vendor['Index_type'] == 'FULLTEXT') ? 'FULLTEXT ' : '') . $word . $this->quoteIdentifier($index->getName()) . "(" . $this->getIndexColumnList($index) . ")";
}
}

View File

@@ -44,6 +44,12 @@ class Index extends XMLElement {
/** @var array */
private $indexColumnSizes = array();
/**
* Index type of this column.
* @var string
*/
private $indexType;
/**
* Creates a new instance with default characteristics (no name or
@@ -192,6 +198,9 @@ class Index extends XMLElement {
if (isset($attrib["size"])) {
$this->indexColumnSizes[$name] = $attrib["size"];
}
if (!empty($attrib["indexType"])) {
$this->indexType = $attrib["indexType"];
}
}
/**
@@ -273,4 +282,13 @@ class Index extends XMLElement {
$result .= " </index>\n";
return $result;
}
/**
* Returns the index type of this column.
* @return string
*/
public function getIndexType()
{
return $this->indexType;
}
}

View File

@@ -38,383 +38,392 @@ include_once 'phing/system/io/FileReader.php';
* @version $Revision: 536 $
* @package propel.engine.database.transform
*/
class XmlToAppData extends AbstractHandler {
/** enables debug output */
const DEBUG = false;
private $app;
private $platform;
private $currDB;
private $currTable;
private $currColumn;
private $currFK;
private $currIndex;
private $currUnique;
private $currValidator;
private $currVendorObject;
private $isForReferenceOnly;
private $currentPackage;
private $currentXmlFile;
private $defaultPackage;
private $encoding;
/** two-dimensional array,
first dimension is for schemas(key is the path to the schema file),
second is for tags within the schema */
private $schemasTagsStack = array();
public $parser;
/**
* Creates a new instance for the specified database type.
*
* @param Platform $platform The type of database for the application.
* @param string $defaultPackage the default PHP package used for the om
* @param string $encoding The database encoding.
*/
public function __construct(Platform $platform, $defaultPackage, $encoding = 'iso-8859-1')
{
$this->app = new AppData($platform);
$this->platform = $platform;
$this->defaultPackage = $defaultPackage;
$this->firstPass = true;
$this->encoding = $encoding;
}
/**
* Parses a XML input file and returns a newly created and
* populated AppData structure.
*
* @param string $xmlFile The input file to parse.
* @return AppData populated by <code>xmlFile</code>.
*/
public function parseFile($xmlFile)
{
// we don't want infinite recursion
if($this->isAlreadyParsed($xmlFile)) {
return;
}
$domDocument = new DomDocument('1.0', 'UTF-8');
$domDocument->load($xmlFile);
// store current schema file path
$this->schemasTagsStack[$xmlFile] = array();
$this->currentXmlFile = $xmlFile;
try {
$fr = new FileReader($xmlFile);
} catch (Exception $e) {
$f = new PhingFile($xmlFile);
throw new Exception("XML File not found: " . $f->getAbsolutePath());
}
$br = new BufferedReader($fr);
$this->parser = new ExpatParser($br);
$this->parser->parserSetOption(XML_OPTION_CASE_FOLDING, 0);
$this->parser->setHandler($this);
try {
$this->parser->parse();
} catch (Exception $e) {
$br->close();
throw $e;
}
$br->close();
array_pop($this->schemasTagsStack);
return $this->app;
}
/**
* Handles opening elements of the xml file.
*
* @param string $uri
* @param string $localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param string $rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
* @param string $attributes The specified or defaulted attributes
*/
public function startElement($name, $attributes) {
try {
$parentTag = $this->peekCurrentSchemaTag();
if ($parentTag === false) {
switch($name) {
case "database":
if ($this->isExternalSchema()) {
$this->currentPackage = @$attributes["package"];
if ($this->currentPackage === null) {
$this->currentPackage = $this->defaultPackage;
}
} else {
$this->currDB = $this->app->addDatabase($attributes);
}
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "database") {
switch($name) {
case "external-schema":
$xmlFile = @$attributes["filename"];
//"referenceOnly" attribute is valid in the main schema XML file only,
//and it's ingnored in the nested external-schemas
if(!$this->isExternalSchema()) {
$isForRefOnly = @$attributes["referenceOnly"];
$this->isForReferenceOnly = ($isForRefOnly !== null ? (strtolower($isForRefOnly) === "true") : true); // defaults to TRUE
}
if ($xmlFile{0} != '/') {
$f = new PhingFile($this->currentXmlFile);
$xf = new PhingFile($f->getParent(), $xmlFile);
$xmlFile = $xf->getPath();
}
$this->parseFile($xmlFile);
break;
case "domain":
$this->currDB->addDomain($attributes);
break;
case "table":
$this->currTable = $this->currDB->addTable($attributes);
if ($this->isExternalSchema()) {
$this->currTable->setForReferenceOnly($this->isForReferenceOnly);
$this->currTable->setPackage($this->currentPackage);
}
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currDB, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "table") {
switch($name) {
case "column":
$this->currColumn = $this->currTable->addColumn($attributes);
break;
case "foreign-key":
$this->currFK = $this->currTable->addForeignKey($attributes);
break;
case "index":
$this->currIndex = $this->currTable->addIndex($attributes);
break;
case "unique":
$this->currUnique = $this->currTable->addUnique($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currTable, $attributes['type']);
break;
case "validator":
$this->currValidator = $this->currTable->addValidator($attributes);
break;
case "id-method-parameter":
$this->currTable->addIdMethodParameter($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "column") {
switch($name) {
case "inheritance":
$this->currColumn->addInheritance($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currColumn, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "foreign-key") {
switch($name) {
case "reference":
$this->currFK->addReference($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currFK, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "index") {
switch($name) {
case "index-column":
$this->currIndex->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currIndex, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "unique") {
switch($name) {
case "unique-column":
$this->currUnique->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currUnique, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "validator") {
switch($name) {
case "rule":
$this->currValidator->addRule($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "vendor") {
switch($name) {
case "parameter":
if($this->currVendorObject->isCompatible($this->platform->getDatabaseType())) {
$this->currVendorObject->setVendorParameter($attributes['name'], iconv('utf-8',$this->encoding, $attributes['value']));
}
break;
default:
$this->_throwInvalidTagException($name);
}
} else {
// it must be an invalid tag
$this->_throwInvalidTagException($name);
}
$this->pushCurrentSchemaTag($name);
} catch (BuildException $e) {
throw $e;
} catch (Exception $e) {
echo $e;
echo "\n";
throw $e;
}
}
function _throwInvalidTagException($tag_name)
{
throw new BuildException("Unexpected tag <" . $tag_name . ">", $this->parser->getLocation());
}
/**
* Handles closing elements of the xml file.
*
* @param uri
* @param localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
*/
public function endElement($name)
{
if (self::DEBUG) {
print("endElement(" . $name . ") called\n");
}
$this->popCurrentSchemaTag();
}
protected function peekCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
return end($this->schemasTagsStack[end($keys)]);
}
protected function popCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
array_pop($this->schemasTagsStack[end($keys)]);
}
protected function pushCurrentSchemaTag($tag)
{
$keys = array_keys($this->schemasTagsStack);
$this->schemasTagsStack[end($keys)][] = $tag;
}
protected function isExternalSchema()
{
return (sizeof($this->schemasTagsStack) > 1);
}
protected function isAlreadyParsed($filePath)
{
return isset($this->schemasTagsStack[$filePath]);
}
class XmlToAppData extends AbstractHandler
{
/** enables debug output */
const DEBUG = false;
private $app;
private $platform;
private $currDB;
private $currTable;
private $currColumn;
private $currFK;
private $currIndex;
private $currUnique;
private $currValidator;
private $currVendorObject;
private $isForReferenceOnly;
private $currentPackage;
private $currentXmlFile;
private $defaultPackage;
private $encoding;
/** two-dimensional array,
* first dimension is for schemas(key is the path to the schema file),
* second is for tags within the schema
*/
private $schemasTagsStack = array();
public $parser;
/**
* Creates a new instance for the specified database type.
*
* @param Platform $platform The type of database for the application.
* @param string $defaultPackage the default PHP package used for the om
* @param string $encoding The database encoding.
*/
public function __construct(Platform $platform, $defaultPackage, $encoding = 'iso-8859-1')
{
$this->app = new AppData($platform);
$this->platform = $platform;
$this->defaultPackage = $defaultPackage;
$this->firstPass = true;
$this->encoding = $encoding;
}
/**
* Parses a XML input file and returns a newly created and
* populated AppData structure.
*
* @param string $xmlFile The input file to parse.
* @return AppData populated by <code>xmlFile</code>.
*/
public function parseFile($xmlFile)
{
// we don't want infinite recursion
if ($this->isAlreadyParsed($xmlFile)) {
return;
}
$domDocument = new DomDocument('1.0', 'UTF-8');
$domDocument->load($xmlFile);
// store current schema file path
$this->schemasTagsStack[$xmlFile] = array();
$this->currentXmlFile = $xmlFile;
try {
$fr = new FileReader($xmlFile);
} catch (Exception $e) {
$f = new PhingFile($xmlFile);
throw new Exception("XML File not found: " . $f->getAbsolutePath());
}
$br = new BufferedReader($fr);
$this->parser = new ExpatParser($br);
$this->parser->parserSetOption(XML_OPTION_CASE_FOLDING, 0);
$this->parser->setHandler($this);
try {
$this->parser->parse();
} catch (Exception $e) {
$br->close();
throw $e;
}
$br->close();
array_pop($this->schemasTagsStack);
return $this->app;
}
/**
* Handles opening elements of the xml file.
*
* @param string $uri
* @param string $localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param string $rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
* @param string $attributes The specified or defaulted attributes
*/
public function startElement($name, $attributes)
{
try {
$parentTag = $this->peekCurrentSchemaTag();
if ($parentTag === false) {
switch ($name) {
case "database":
if ($this->isExternalSchema()) {
$this->currentPackage = @$attributes["package"];
if ($this->currentPackage === null) {
$this->currentPackage = $this->defaultPackage;
}
} else {
$this->currDB = $this->app->addDatabase($attributes);
}
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "database") {
switch ($name) {
case "external-schema":
$xmlFile = @$attributes["filename"];
//"referenceOnly" attribute is valid in the main schema XML file only,
//and it's ingnored in the nested external-schemas
if (!$this->isExternalSchema()) {
$isForRefOnly = @$attributes["referenceOnly"];
$this->isForReferenceOnly = ($isForRefOnly !== null ? (strtolower($isForRefOnly) === "true") : true); // defaults to TRUE
}
if ($xmlFile{0} != '/') {
$f = new PhingFile($this->currentXmlFile);
$xf = new PhingFile($f->getParent(), $xmlFile);
$xmlFile = $xf->getPath();
}
$this->parseFile($xmlFile);
break;
case "domain":
$this->currDB->addDomain($attributes);
break;
case "table":
$this->currTable = $this->currDB->addTable($attributes);
if ($this->isExternalSchema()) {
$this->currTable->setForReferenceOnly($this->isForReferenceOnly);
$this->currTable->setPackage($this->currentPackage);
}
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currDB, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "table") {
switch ($name) {
case "column":
$this->currColumn = $this->currTable->addColumn($attributes);
break;
case "foreign-key":
$this->currFK = $this->currTable->addForeignKey($attributes);
break;
case "index":
$this->currIndex = $this->currTable->addIndex($attributes);
break;
case "fulltext":
$this->currIndex = $this->currTable->addIndex($attributes);
break;
case "unique":
$this->currUnique = $this->currTable->addUnique($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currTable, $attributes['type']);
break;
case "validator":
$this->currValidator = $this->currTable->addValidator($attributes);
break;
case "id-method-parameter":
$this->currTable->addIdMethodParameter($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "column") {
switch ($name) {
case "inheritance":
$this->currColumn->addInheritance($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currColumn, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "foreign-key") {
switch ($name) {
case "reference":
$this->currFK->addReference($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currFK, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "index") {
switch ($name) {
case "index-column":
$this->currIndex->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currIndex, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "fulltext") {
switch ($name) {
case "index-column":
$attributes['indexType'] = "FULLTEXT";
$this->currIndex->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currIndex, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "unique") {
switch ($name) {
case "unique-column":
$this->currUnique->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = new ObjectWithVendorSpecificData($this->currUnique, $attributes['type']);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "validator") {
switch ($name) {
case "rule":
$this->currValidator->addRule($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "vendor") {
switch ($name) {
case "parameter":
if ($this->currVendorObject->isCompatible($this->platform->getDatabaseType())) {
$this->currVendorObject->setVendorParameter($attributes['name'], iconv('utf-8', $this->encoding, $attributes['value']));
}
break;
default:
$this->_throwInvalidTagException($name);
}
} else {
// it must be an invalid tag
$this->_throwInvalidTagException($name);
}
$this->pushCurrentSchemaTag($name);
} catch (BuildException $e) {
throw $e;
} catch (Exception $e) {
echo $e;
echo "\n";
throw $e;
}
}
function _throwInvalidTagException($tag_name)
{
throw new BuildException("Unexpected tag <" . $tag_name . ">", $this->parser->getLocation());
}
/**
* Handles closing elements of the xml file.
*
* @param uri
* @param localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
*/
public function endElement($name)
{
if (self::DEBUG) {
print("endElement(" . $name . ") called\n");
}
$this->popCurrentSchemaTag();
}
protected function peekCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
return end($this->schemasTagsStack[end($keys)]);
}
protected function popCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
array_pop($this->schemasTagsStack[end($keys)]);
}
protected function pushCurrentSchemaTag($tag)
{
$keys = array_keys($this->schemasTagsStack);
$this->schemasTagsStack[end($keys)][] = $tag;
}
protected function isExternalSchema()
{
return (sizeof($this->schemasTagsStack) > 1);
}
protected function isAlreadyParsed($filePath)
{
return isset($this->schemasTagsStack[$filePath]);
}
}
/**
* Utility class used for objects with vendor data.
*
* @package propel.engine.database.transform
* @package propel.engine.database.transform
*/
class ObjectWithVendorSpecificData
{
protected $object;
protected $vendorType;
protected $object;
protected $vendorType;
public function __construct($object, $vendorType)
{
$this->object = $object;
$this->vendorType = $vendorType;
}
public function __construct($object, $vendorType)
{
$this->object = $object;
$this->vendorType = $vendorType;
}
public function isCompatible($type)
{
return ($this->vendorType == $type);
}
public function isCompatible($type)
{
return ($this->vendorType == $type);
}
public function setVendorParameter($name, $value)
{
$this->object->setVendorParameter($name, $value);
}
public function setVendorParameter($name, $value)
{
$this->object->setVendorParameter($name, $value);
}
}

View File

@@ -42,7 +42,7 @@ PHP class or method name.
note: the interface="true", requires that useManagers=true in the
properties file.
-->
<!ELEMENT table (column+,(foreign-key|index|unique|id-method-parameter|validator|vendor)*)>
<!ELEMENT table (column+,(foreign-key|index|fulltext|unique|id-method-parameter|validator|vendor)*)>
<!ATTLIST table
name CDATA #REQUIRED
phpName CDATA #IMPLIED
@@ -122,6 +122,11 @@ PHP class or method name.
name CDATA #IMPLIED
>
<!ELEMENT fulltext (index-column+)>
<!ATTLIST fulltext
name CDATA #IMPLIED
>
<!ELEMENT index-column (vendor*)>
<!ATTLIST index-column
name CDATA #REQUIRED

View File

@@ -225,6 +225,14 @@
<xs:attribute name="name" type="index_name" use="optional"/>
</xs:complexType>
<xs:complexType name="fulltext">
<xs:choice maxOccurs="unbounded">
<xs:element name="index-column" type="index-column" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="vendor" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
<xs:attribute name="name" type="index_name" use="optional"/>
</xs:complexType>
<xs:complexType name="unique">
<xs:choice maxOccurs="unbounded">
<xs:element name="unique-column" type="unique-column" minOccurs="1" maxOccurs="unbounded"/>
@@ -307,6 +315,7 @@
<xs:element name="column" type="column" maxOccurs="unbounded"/>
<xs:element name="foreign-key" type="foreign-key" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="index" type="index" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="fulltext" type="fulltext" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="unique" type="unique" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="id-method-parameter" type="id-method-parameter" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="validator" type="validator" minOccurs="0" maxOccurs="unbounded"/>

View File

@@ -101,6 +101,7 @@
<xsl:apply-templates select='column'/>
<xsl:apply-templates select='foreign-key'/>
<xsl:apply-templates select='index'/>
<xsl:apply-templates select='fulltext'/>
<xsl:apply-templates select='unique'/>
<xsl:apply-templates select='id-method-parameter'/>
<xsl:apply-templates select='validator'/>
@@ -129,6 +130,13 @@
</index>
</xsl:template>
<xsl:template match='fulltext'>
<fulltext>
<xsl:apply-templates select='@*'/>
<xsl:apply-templates select='index-column'/>
</fulltext>
</xsl:template>
<xsl:template match='unique'>
<unique>
<xsl:apply-templates select='@*'/>