diff --git a/.gitignore b/.gitignore
index 489ded2..dd778a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@ Thumbs.db
.settings/
.build/
.idea/
-nbproject/
\ No newline at end of file
+nbproject/
+/vendor
diff --git a/assets/.htaccess b/assets/.htaccess
deleted file mode 100644
index ba5cc4f..0000000
--- a/assets/.htaccess
+++ /dev/null
@@ -1,7 +0,0 @@
-
- Order allow,deny
- Allow from all
-
-
- Require all granted
-
diff --git a/classes/DC_Multilingual_Query.php b/classes/DC_Multilingual_Query.php
deleted file mode 100644
index c81b23d..0000000
--- a/classes/DC_Multilingual_Query.php
+++ /dev/null
@@ -1,157 +0,0 @@
-
- * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
- * @link http://github.com/terminal42/contao-dc_multilingual
- */
-
-
-/**
- * Create a Query for a DC_Multilingual table
- */
-class DC_Multilingual_Query
-{
-
- protected $strTable = '';
- protected $arrFields = array();
- protected $arrWhere = array();
- protected $arrOrder = array();
- protected $arrJoin = array();
-
- /**
- * @var string Language to fetch
- */
- public $language = '';
-
-
- /**
- * Construct the QueryBuilder.
- *
- * If you need to reference the table you have
- * * t1 for the base-fields
- * * t2 for the language-fields
- *
- * @param string $strTable
- *
- * @return DC_Multilingual_Query current instance
- */
- public function __construct($strTable)
- {
- $this->strTable = $strTable;
-
- // Load DataContainer if its not already done
- if (!is_array($GLOBALS['TL_DCA'][$this->strTable])) {
- $loader = new \DcaLoader($strTable);
- $loader->load();
- }
-
- // add multilingual fields
- foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'] as $field => $arrData) {
- if ($arrData['eval']['translatableFor'] == '') continue;
- $this->arrFields[] = "IFNULL(t2.$field, t1.$field) AS $field";
- }
-
- // set default language
- $this->language = str_replace('-', '_', $GLOBALS['TL_LANGUAGE']);
-
- return $this;
- }
-
-
- /**
- * Add a field
- *
- * @param string $strField fielname
- *
- * @return DC_Multilingual_Query current instance
- */
- public function addField($strField)
- {
- $this->arrFields[] = $strField;
-
- return $this;
- }
-
-
- /**
- * Add a WHERE-constraint
- * all WHERE-pieces glued with AND
- *
- * @param string $strWhere
- *
- * @return DC_Multilingual_Query current instance
- */
- public function addWhere($strWhere)
- {
- $this->arrWhere[] = $strWhere;
-
- return $this;
- }
-
-
- /**
- * Add a JOIN-statement
- *
- * @param string $strJoin
- *
- * @return DC_Multilingual_Query current instance
- */
- public function addJoin($strJoin)
- {
- $this->arrJoin[] = $strJoin;
-
- return $this;
- }
-
-
- /**
- * Add a ORDER-constraint
- *
- * @param string $strOrderfield
- *
- * @return DC_Multilingual_Query current instance
- */
- public function addOrder($strOrderfield)
- {
- $this->arrOrder[] = $strOrderfield;
-
- return $this;
- }
-
-
- /**
- * Returns the query
- *
- * @return string
- */
- public function getQuery()
- {
- $strPid = \DC_Multilingual::getPidColumnForTable($this->strTable);
- $strLang = \DC_Multilingual::getLanguageColumnForTable($this->strTable);
-
- return "
-SELECT t1.*,
- " . implode(', ', $this->arrFields) . "
-FROM {$this->strTable} AS t1
-LEFT OUTER JOIN {$this->strTable} AS t2 ON (t1.id=t2.$strPid AND t2.$strLang='{$this->language}') " .
- implode(' ', $this->arrJoin) . "
-WHERE t1.$strPid=0" .
- (count($this->arrWhere) ? ' AND (' . implode(' AND ', $this->arrWhere) . ')' : '') .
- (count($this->arrOrder) ? ' ORDER BY ' . implode(',', $this->arrOrder) : '');
- }
-
-
- /**
- * Returns the Database_Statement for the query
- *
- * @return \Database\Statement
- */
- public function getStatement()
- {
- return \Database::getInstance()->prepare($this->getQuery());
- }
-}
diff --git a/classes/MultilingualQueryBuilder.php b/classes/MultilingualQueryBuilder.php
deleted file mode 100644
index fbf4472..0000000
--- a/classes/MultilingualQueryBuilder.php
+++ /dev/null
@@ -1,146 +0,0 @@
-
- * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
- * @link http://github.com/terminal42/contao-dc_multilingual
- */
-
-
-/**
- * Class MultilingualQueryBuilder
- *
- * The class reads the relation meta data from the DCA and creates the necessary
- * JOIN queries to retrieve an object from the database.
- */
-class MultilingualQueryBuilder
-{
-
- /**
- * Build a query based on the given options
- *
- * @param array $arrOptions The options array
- *
- * @return string The query string
- *
- * @throws \BadMethodCallException
- */
- public static function find($arrOptions)
- {
- $arrLanguageFields = static::getMultilingualFields($arrOptions['table']);
- $strPid = \DC_Multilingual::getPidColumnForTable($arrOptions['table']);
- $strLang = \DC_Multilingual::getLanguageColumnForTable($arrOptions['table']);
-
- // Use the current language if none provided
- if (!isset($arrOptions['language'])) {
- $arrOptions['language'] = str_replace('-', '_', $GLOBALS['TL_LANGUAGE']);
- }
-
- // Consider the fallback language
- $fallbackLang = \DC_Multilingual::getFallbackLanguageForTable($arrOptions['table']);
- if (null !== $fallbackLang
- && $fallbackLang === $arrOptions['language']
- ) {
- $arrOptions['language'] = '';
- }
-
-
- $strQuery = "SELECT dcm1.*" . (!empty($arrLanguageFields) ? (", " . implode(", ", static::generateFieldsSubquery($arrLanguageFields, 'dcm1', 'dcm2'))) : "") . " FROM " . $arrOptions['table'] . " AS dcm1";
-
- // Fetch language fields
- if (!empty($arrLanguageFields)) {
- $strQuery .= " LEFT OUTER JOIN " . $arrOptions['table'] . " AS dcm2 ON (dcm1.id=dcm2." . $strPid . " AND dcm2.$strLang='" . $arrOptions['language'] . "')";
- }
-
- $strQuery .= " WHERE dcm1.$strPid=0";
-
- // Where condition
- if ($arrOptions['column'] !== null) {
- $strQuery .= " AND " . str_replace($arrOptions['table'] . ".", "dcm1.", (is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?"));
- }
-
- // Group by
- if ($arrOptions['group'] !== null) {
- $strQuery .= " GROUP BY " . str_replace($arrOptions['table'] . ".", "dcm1.", $arrOptions['group']);
- }
-
- // Order by
- if ($arrOptions['order'] !== null) {
- $strQuery .= " ORDER BY " . str_replace($arrOptions['table'] . ".", "dcm1.", $arrOptions['order']);
- }
-
- return $strQuery;
- }
-
-
- /**
- * Build a query based on the given options to count the number of records
- *
- * @param array $arrOptions The options array
- *
- * @return string The query string
- */
- public static function count($arrOptions)
- {
- $strPid = \DC_Multilingual::getPidColumnForTable($arrOptions['table']);
- $strQuery = "SELECT COUNT(*) AS count FROM " . $arrOptions['table'] . " WHERE $strPid=0";
-
- if ($arrOptions['column'] !== null) {
- $strQuery .= " AND " . (is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?");
- }
-
- return $strQuery;
- }
-
-
- /**
- * Get the multilingual fields as array
- *
- * @param string
- *
- * @return array
- */
- public static function getMultilingualFields($strTable)
- {
- $arrFields = array();
-
- \Controller::loadDataContainer($strTable);
-
- foreach ($GLOBALS['TL_DCA'][$strTable]['fields'] as $k => $v) {
- if ($v['eval']['translatableFor']) {
- $arrFields[] = $k;
- }
- }
-
- return $arrFields;
- }
-
-
- /**
- * Generate the fields subquery and return it as array
- *
- * @param mixed
- * @param string
- * @param string
- * @param string
- *
- * @return mixed
- */
- public static function generateFieldsSubquery($varFields, $strFirstTable, $strSecondTable, $strPrefix = '')
- {
- if (is_array($varFields)) {
- $arrReturn = array();
-
- foreach ($varFields as $field) {
- $arrReturn[] = static::generateFieldsSubquery($field, $strFirstTable, $strSecondTable, $strPrefix);
- }
-
- return $arrReturn;
- }
-
- return "IFNULL(" . $strSecondTable . "." . $varFields . ", " . $strFirstTable . "." . $varFields . ") AS " . (strlen($strPrefix) ? $strPrefix : "") . $varFields;
- }
-}
diff --git a/composer.json b/composer.json
index bbba4d0..744db5b 100644
--- a/composer.json
+++ b/composer.json
@@ -15,18 +15,16 @@
}
],
"require":{
- "php":">=5.3.2",
- "contao/core-bundle":"^3.3 || ^4.1",
- "contao-community-alliance/composer-plugin":"^2.4.0 || 3.*"
+ "php":">=5.4",
+ "contao/core-bundle":"^4.1",
+ "doctrine/orm": "^2.5"
},
- "replace": {
- "contao-legacy/dc_multilingual": "self.version"
- },
- "extra":{
- "contao": {
- "sources":{
- "":"system/modules/dc_multilingual"
- }
+ "autoload": {
+ "classmap": [
+ "src/DC_Multilingual.php"
+ ],
+ "psr-4": {
+ "Terminal42\\DcMultilingualBundle\\": "src"
}
}
}
diff --git a/config/autoload.ini b/config/autoload.ini
deleted file mode 100644
index 780bb3e..0000000
--- a/config/autoload.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-
-;;
-; List modules which are required to be loaded beforehand
-;;
-requires[] = "core"
-
-;;
-; Configure what you want the autoload creator to register
-;;
-register_namespaces = false
-register_classes = false
-register_templates = false
diff --git a/config/autoload.php b/config/autoload.php
deleted file mode 100644
index f090b3d..0000000
--- a/config/autoload.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
- * @link http://github.com/terminal42/contao-dc_multilingual
- */
-
-
-/**
- * Register the classes
- */
-ClassLoader::addClasses(array
-(
- 'DC_Multilingual' => 'system/modules/dc_multilingual/drivers/DC_Multilingual.php',
- 'MultilingualModel' => 'system/modules/dc_multilingual/models/MultilingualModel.php',
- 'MultilingualQueryBuilder' => 'system/modules/dc_multilingual/classes/MultilingualQueryBuilder.php',
- 'DC_Multilingual_Query' => 'system/modules/dc_multilingual/classes/DC_Multilingual_Query.php'
-));
diff --git a/models/MultilingualModel.php b/models/MultilingualModel.php
deleted file mode 100644
index 7868cf5..0000000
--- a/models/MultilingualModel.php
+++ /dev/null
@@ -1,60 +0,0 @@
-
- * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
- * @link http://github.com/terminal42/contao-dc_multilingual
- */
-
-
-/**
- * Class MultilingualModel
- *
- * Provide methods to handle multilingual models
- */
-abstract class MultilingualModel extends \Model
-{
-
- /**
- * Use the multilingual query
- * @param boolean
- */
- protected static $blnMultilingual = true;
-
-
- /**
- * Build a query based on the given options
- *
- * @param array $arrOptions The options array
- *
- * @return string The query string
- */
- protected static function buildFindQuery(array $arrOptions)
- {
- if (static::$blnMultilingual === false) {
- return parent::buildFindQuery($arrOptions);
- }
-
- return \MultilingualQueryBuilder::find($arrOptions);
- }
-
-
- /**
- * Build a query based on the given options to count the number of records
- *
- * @param array $arrOptions The options array
- *
- * @return string The query string
- */
- protected static function buildCountQuery(array $arrOptions)
- {
- if (static::$blnMultilingual === false) {
- return parent::buildCountQuery($arrOptions);
- }
-
- return \MultilingualQueryBuilder::count($arrOptions);
- }
-}
diff --git a/src/DC_Multilingual.php b/src/DC_Multilingual.php
new file mode 100644
index 0000000..245ccdc
--- /dev/null
+++ b/src/DC_Multilingual.php
@@ -0,0 +1,11 @@
+
+ * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
+ * @link http://github.com/terminal42/contao-dc_multilingual
+ */
+class DC_Multilingual extends \Terminal42\DcMultilingualBundle\Driver {}
diff --git a/drivers/DC_Multilingual.php b/src/Driver.php
similarity index 99%
rename from drivers/DC_Multilingual.php
rename to src/Driver.php
index c859663..fef90b4 100644
--- a/drivers/DC_Multilingual.php
+++ b/src/Driver.php
@@ -9,21 +9,11 @@
* @link http://github.com/terminal42/contao-dc_multilingual
*/
+namespace Terminal42\DcMultilingualBundle;
-/**
- * Class DC_Multilingual
- *
- * Provide methods to handle multilingual DC_Table entries
- *
- * @copyright terminal42 gmbh 2011-2012
- * @author Yanick Witschi
- * @author Andreas Schempp
- * @author Kamil Kuzminski
- * @package dc_multilingual
- */
-class DC_Multilingual extends \DC_Table
-{
+class Driver extends \DC_Table
+{
/**
* True if we are editing a language that is not the fallback
*
@@ -97,7 +87,7 @@ public function __construct($strTable)
$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['filter'][] = array($this->strLangColumn . '=?', '');
- $GLOBALS['TL_CSS'][] = 'system/modules/dc_multilingual/assets/backend.min.css';
+ $GLOBALS['TL_CSS'][] = 'bundles/terminal42dcmultilingual/backend.min.css';
}
@@ -885,10 +875,11 @@ public function ajaxTreeView($id, $level)
* @param boolean
* @param boolean
* @param boolean
+ * @param array
*
* @return string
*/
- protected function generateTree($table, $id, $arrPrevNext, $blnHasSorting, $intMargin = 0, $arrClipboard = null, $blnCircularReference = false, $protectedPage = false, $blnNoRecursion = false)
+ protected function generateTree($table, $id, $arrPrevNext, $blnHasSorting, $intMargin = 0, $arrClipboard = null, $blnCircularReference = false, $protectedPage = false, $blnNoRecursion = false, $arrFound=array())
{
$session = $this->Session->getData();
$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable . '_' . $table . '_tree' : $this->strTable . '_tree';
diff --git a/src/Model/Multilingual.php b/src/Model/Multilingual.php
new file mode 100644
index 0000000..29d677d
--- /dev/null
+++ b/src/Model/Multilingual.php
@@ -0,0 +1,188 @@
+
+ * @license http://opensource.org/licenses/lgpl-3.0.html LGPL
+ * @link http://github.com/terminal42/contao-dc_multilingual
+ */
+
+namespace Terminal42\DcMultilingualBundle\Model;
+
+use Doctrine\DBAL\Query\QueryBuilder;
+use Terminal42\DcMultilingualBundle\QueryBuilder\MultilingualQueryBuilderFactoryInterface;
+
+class Multilingual extends \Model
+{
+ /**
+ * Build a query based on the given options
+ *
+ * @param array $options The options array
+ *
+ * @return string The query string
+ */
+ protected static function buildFindQuery(array $options)
+ {
+ $qb = static::getQueryBuilder();
+
+ static::applyOptionsToQueryBuilder($qb, $options);
+
+ return $qb->getQueryBuilder()->getSQL();
+
+ }
+
+ /**
+ * Build a query based on the given options to count the number of records
+ *
+ * @param array $options The options array
+ *
+ * @return string The query string
+ */
+ protected static function buildCountQuery(array $options)
+ {
+ $qb = static::getQueryBuilder();
+
+ static::applyOptionsToQueryBuilder($qb, $options);
+
+ return $qb->getQueryBuilder()->getSQL();
+ }
+
+ /**
+ * Apply the model options to the query builder.
+ *
+ * @param QueryBuilder $qb
+ * @param array $options
+ */
+ protected static function applyOptionsToQueryBuilder(QueryBuilder $qb, array $options)
+ {
+ // Use the current language if none provided
+ if (!isset($options['language'])) {
+ $options['language'] = str_replace('-', '_', $GLOBALS['TL_LANGUAGE']);
+ }
+
+ // Consider the fallback language
+ $fallbackLang = static::getFallbackLanguage();
+ if (null !== $fallbackLang && $fallbackLang === $options['language']) {
+ $options['language'] = '';
+ }
+
+ // Columns
+ if (null !== $options['column']) {
+ if (is_array($options['column'])) {
+ foreach ($options['column'] as $column) {
+ $qb->andWhere($column);
+ }
+ } else {
+ $qb->andWhere($options['table'] . '.' . options['column'] . '=?');
+ }
+ }
+
+ // Group by
+ if (null !== $options['group']) {
+ $qb->groupBy($options['group']);
+ }
+
+ // Order by
+ if (null !== $options['order']) {
+ $qb->add('orderBy', $options['order']);
+ }
+ }
+
+ /**
+ * Get QueryBuilder.
+ *
+ * @return \Terminal42\DcMultilingualBundle\MultilingualQueryBuilderInterface
+ */
+ protected static function getQueryBuilder()
+ {
+ /** @var MultilingualQueryBuilderFactoryInterface $factory */
+ $factory = \System::getContainer()->get('terminal42.dc_multilingual.querybuilder_factory');
+
+ return $factory->build(
+ static::getTable(),
+ static::getPidColumn(),
+ static::getLangColumn(),
+ static::getRegularFields(),
+ static::getTranslatableFields()
+ );
+ }
+
+ /**
+ * Get the regular fields
+ *
+ * @return array
+ */
+ protected static function getRegularFields()
+ {
+ $extractor = \DcaExtractor::getInstance(static::getTable());
+
+ return array_keys($extractor->getFields());
+ }
+
+ /**
+ * Get the fields that are translatable.
+ *
+ * @return array
+ */
+ protected static function getTranslatableFields()
+ {
+ $fields = [];
+
+ foreach ($GLOBALS['TL_DCA'][static::getTable()]['fields'] as $field => $data) {
+ if (!isset($data['eval']['translatableFor'])) {
+ continue;
+ }
+
+ $fields[] = $field;
+ }
+
+ return $fields;
+ }
+
+ /**
+ * Get the PID column.
+ *
+ * @return string
+ */
+ protected static function getPidColumn()
+ {
+ if ($GLOBALS['TL_DCA'][static::getTable()]['config']['langPid']) {
+
+ return $GLOBALS['TL_DCA'][static::getTable()]['config']['langPid'];
+ }
+
+ return 'langPid';
+ }
+
+ /**
+ * Get the language column.
+ *
+ * @return string
+ */
+ public static function getLangColumn()
+ {
+ if ($GLOBALS['TL_DCA'][static::getTable()]['config']['langColumn']) {
+
+ return $GLOBALS['TL_DCA'][static::getTable()]['config']['langColumn'];
+ }
+
+ return 'language';
+ }
+
+ /**
+ * Get the fallback language if available.
+ *
+ * @return string|null
+ */
+ public static function getFallbackLanguage()
+ {
+ if ($GLOBALS['TL_DCA'][static::getTable()]['config']['fallbackLang']) {
+
+ return $GLOBALS['TL_DCA'][static::getTable()]['config']['fallbackLang'];
+ }
+
+ return null;
+ }
+}
diff --git a/src/QueryBuilder/MultilingualQueryBuilder.php b/src/QueryBuilder/MultilingualQueryBuilder.php
new file mode 100644
index 0000000..eb5875c
--- /dev/null
+++ b/src/QueryBuilder/MultilingualQueryBuilder.php
@@ -0,0 +1,122 @@
+qb = $qb;
+ $this->table = $table;
+ $this->langColumnName = $langColumnName;
+ $this->pidColumnName = $pidColumnName;
+ $this->regularFields = $regularFields;
+ $this->translatableFields = $translatableFields;
+ }
+
+ /**
+ * Build the query for a simple count query.
+ */
+ public function getQueryBuilderForCount()
+ {
+ $this->qb->resetQueryParts();
+
+ $this->qb->addSelect('COUNT(id) AS count')
+ ->from($this->table)
+ ->where("{$this->pidColumnName}=0");
+ }
+
+ /**
+ * Build the query builder for a find query.
+ *
+ * @param string $language
+ */
+ public function buildQueryBuilderForFind($language)
+ {
+ $this->qb->resetQueryParts();
+
+ // Regular fields
+ foreach ($this->regularFields as $field) {
+ $this->qb->addSelect("t1.$field");
+ }
+
+ // Translatable fields
+ foreach ($this->translatableFields as $field) {
+ $this->qb->addSelect("IFNULL(t2.$field, t1.$field) AS $field");
+ }
+
+ $this->qb->from($this->table, 't1');
+ $this->qb->add('join', [
+ [
+ 'joinType' => 'left outer',
+ 'joinTable' => $this->table,
+ 'joinAlias' => 't2',
+ 'condition' => "t1.id=t2.{$this->pidColumnName} AND t2.{$this->langColumnName}='$language')"
+ ]
+ ], true);
+
+ $this->qb->where("t1.{$this->pidColumnName}=0");
+ }
+
+ /**
+ * @return QueryBuilder
+ */
+ public function getQueryBuilder()
+ {
+ return $this->qb;
+ }
+}
diff --git a/src/QueryBuilder/MultilingualQueryBuilderFactory.php b/src/QueryBuilder/MultilingualQueryBuilderFactory.php
new file mode 100644
index 0000000..8cab10e
--- /dev/null
+++ b/src/QueryBuilder/MultilingualQueryBuilderFactory.php
@@ -0,0 +1,63 @@
+connection = $connection;
+ }
+
+ /**
+ * Builds a MultilingualQueryBuilder.
+ *
+ * @param string $table
+ * @param string $pidColumnName
+ * @param string $langColumnName
+ * @param array $regularFields
+ * @param array $translatableFields
+ *
+ * @return MultilingualQueryBuilderInterface
+ */
+ public function build(
+ $table,
+ $pidColumnName,
+ $langColumnName,
+ array $regularFields,
+ array $translatableFields
+ ) {
+
+ return new MultilingualQueryBuilder(
+ $this->createQueryBuilder(),
+ $table,
+ $pidColumnName,
+ $langColumnName,
+ $regularFields,
+ $translatableFields
+ );
+ }
+
+ /**
+ * @return QueryBuilder
+ */
+ protected function createQueryBuilder()
+ {
+ return new QueryBuilder($this->connection);
+ }
+}
diff --git a/src/QueryBuilder/MultilingualQueryBuilderFactoryInterface.php b/src/QueryBuilder/MultilingualQueryBuilderFactoryInterface.php
new file mode 100644
index 0000000..7f3ab25
--- /dev/null
+++ b/src/QueryBuilder/MultilingualQueryBuilderFactoryInterface.php
@@ -0,0 +1,27 @@
+