From 388c3ec188219d0470ead4f6ae9a497aca962cfc Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Fri, 16 Aug 2019 16:57:09 +0200 Subject: [PATCH] reduce field size to 150 chars to prevent index out of length (#1031) --- UPGRADING.md | 3 + src/Entity/Activity.php | 8 ++- src/Entity/Customer.php | 27 ++++++-- src/Entity/InvoiceTemplate.php | 4 +- src/Entity/Project.php | 8 ++- src/Entity/Timesheet.php | 2 +- src/Migrations/Version20190706224219.php | 15 +++++ src/Migrations/Version20190813162649.php | 78 +++++++++++++++++++++++ var/data/kimai_test.sqlite | Bin 770048 -> 770048 bytes 9 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 src/Migrations/Version20190813162649.php diff --git a/UPGRADING.md b/UPGRADING.md index 6ae7c1ce..790d551b 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -14,6 +14,9 @@ Perform EACH version specific task between your version and the new one, otherwi - Deleted timezone conversion command. If you are still using 0.7 or below, you need to upgrade to 1.1 before upgrading to this version. - Minimum password length raised from 5 to 8 character (applies only for password changes and new users) +- Maximum customer name length lowered to 150 character +- Maximum project name length lowered to 150 character +- Maximum activity name length lowered to 150 character ## [1.1](https://github.com/kevinpapst/kimai2/releases/tag/1.1) diff --git a/src/Entity/Activity.php b/src/Entity/Activity.php index 9cef4507..4d16f161 100644 --- a/src/Entity/Activity.php +++ b/src/Entity/Activity.php @@ -50,16 +50,18 @@ class Activity implements EntityWithMetaFields /** * @var string * - * @ORM\Column(name="name", type="string", length=255, nullable=false) + * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. + * + * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=255) + * @Assert\Length(min=2, max=150) */ private $name; /** * @var string * - * @ORM\Column(name="comment", type="text", length=65535, nullable=true) + * @ORM\Column(name="comment", type="text", nullable=true) */ private $comment; diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index e33ddb55..3b0f9652 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -40,9 +40,11 @@ class Customer implements EntityWithMetaFields /** * @var string * - * @ORM\Column(name="name", type="string", length=255, nullable=false) + * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. + * + * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotBlank() - * @Assert\Length(min=2, max=255) + * @Assert\Length(min=2, max=150) */ private $name; @@ -50,13 +52,14 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="number", type="string", length=50, nullable=true) + * @Assert\Length(max=50) */ private $number; /** * @var string * - * @ORM\Column(name="comment", type="text", length=65535, nullable=true) + * @ORM\Column(name="comment", type="text", nullable=true) */ private $comment; @@ -72,6 +75,7 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="company", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $company; @@ -79,13 +83,14 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="contact", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $contact; /** * @var string * - * @ORM\Column(name="address", type="text", length=65535, nullable=true) + * @ORM\Column(name="address", type="text", nullable=true) */ private $address; @@ -94,6 +99,7 @@ class Customer implements EntityWithMetaFields * * @ORM\Column(name="country", type="string", length=2, nullable=false) * @Assert\NotBlank() + * @Assert\Length(max=2) */ private $country; @@ -102,6 +108,7 @@ class Customer implements EntityWithMetaFields * * @ORM\Column(name="currency", type="string", length=3, nullable=false) * @Assert\NotBlank() + * @Assert\Length(max=3) */ private $currency = self::DEFAULT_CURRENCY; @@ -109,6 +116,7 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="phone", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $phone; @@ -116,6 +124,7 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="fax", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $fax; @@ -123,13 +132,17 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="mobile", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $mobile; /** * @var string * + * Limited via RFC to 254 chars + * * @ORM\Column(name="email", type="string", length=255, nullable=true) + * @Assert\Length(max=254) */ private $email; @@ -137,14 +150,18 @@ class Customer implements EntityWithMetaFields * @var string * * @ORM\Column(name="homepage", type="string", length=255, nullable=true) + * @Assert\Length(max=255) */ private $homepage; /** * @var string * - * @ORM\Column(name="timezone", type="string", length=255, nullable=false) + * Length was determined by a MySQL column via "use mysql;describe time_zone_name;" + * + * @ORM\Column(name="timezone", type="string", length=64, nullable=false) * @Assert\NotBlank() + * @Assert\Length(max=64) */ private $timezone; diff --git a/src/Entity/InvoiceTemplate.php b/src/Entity/InvoiceTemplate.php index cd30f04c..4f891e2c 100644 --- a/src/Entity/InvoiceTemplate.php +++ b/src/Entity/InvoiceTemplate.php @@ -59,7 +59,7 @@ class InvoiceTemplate /** * @var string * - * @ORM\Column(name="address", type="text", length=65535, nullable=true) + * @ORM\Column(name="address", type="text", nullable=true) */ private $address; @@ -105,7 +105,7 @@ class InvoiceTemplate /** * @var string * - * @ORM\Column(name="payment_terms", type="text", length=65535, nullable=true) + * @ORM\Column(name="payment_terms", type="text", nullable=true) */ private $paymentTerms; diff --git a/src/Entity/Project.php b/src/Entity/Project.php index b2ddc8ae..f39d5420 100644 --- a/src/Entity/Project.php +++ b/src/Entity/Project.php @@ -49,9 +49,11 @@ class Project implements EntityWithMetaFields /** * @var string * - * @ORM\Column(name="name", type="string", length=255, nullable=false) + * Do not increase length to more than 190 chars, otherwise "Index column size too large." will be triggered. + * + * @ORM\Column(name="name", type="string", length=150, nullable=false) * @Assert\NotNull() - * @Assert\Length(min=2, max=255) + * @Assert\Length(min=2, max=150) */ private $name; @@ -66,7 +68,7 @@ class Project implements EntityWithMetaFields /** * @var string * - * @ORM\Column(name="comment", type="text", length=65535, nullable=true) + * @ORM\Column(name="comment", type="text", nullable=true) */ private $comment; diff --git a/src/Entity/Timesheet.php b/src/Entity/Timesheet.php index c2461c9c..b923243e 100644 --- a/src/Entity/Timesheet.php +++ b/src/Entity/Timesheet.php @@ -114,7 +114,7 @@ class Timesheet implements EntityWithMetaFields /** * @var string * - * @ORM\Column(name="description", type="text", length=65535, nullable=true) + * @ORM\Column(name="description", type="text", nullable=true) */ private $description; diff --git a/src/Migrations/Version20190706224219.php b/src/Migrations/Version20190706224219.php index ab07ca90..9ea49d9d 100644 --- a/src/Migrations/Version20190706224219.php +++ b/src/Migrations/Version20190706224219.php @@ -50,15 +50,27 @@ final class Version20190706224219 extends AbstractMigration $timesheet->addIndex(['start_time', 'end_time', 'user'], 'IDX_4F60C6B1502DF587415614018D93D649'); $activity = $schema->getTable('kimai2_activities'); + $name = $activity->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } $activity->addIndex(['visible', 'project_id'], 'IDX_8811FE1C7AB0E859166D1F9C'); $activity->addIndex(['visible', 'project_id', 'name'], 'IDX_8811FE1C7AB0E859166D1F9C5E237E06'); $activity->addIndex(['visible', 'name'], 'IDX_8811FE1C7AB0E8595E237E06'); $project = $schema->getTable('kimai2_projects'); + $name = $project->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } $project->addIndex(['customer_id', 'visible', 'name'], 'IDX_407F12069395C3F37AB0E8595E237E06'); $project->addIndex(['customer_id', 'visible', 'id'], 'IDX_407F12069395C3F37AB0E859BF396750'); $customer = $schema->getTable('kimai2_customers'); + $name = $customer->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } $customer->addIndex(['visible'], 'IDX_5A9760447AB0E859'); } @@ -68,13 +80,16 @@ final class Version20190706224219 extends AbstractMigration $activity->dropIndex('IDX_8811FE1C7AB0E859166D1F9C'); $activity->dropIndex('IDX_8811FE1C7AB0E859166D1F9C5E237E06'); $activity->dropIndex('IDX_8811FE1C7AB0E8595E237E06'); + $activity->getColumn('name')->setLength(255); $customer = $schema->getTable('kimai2_customers'); $customer->dropIndex('IDX_5A9760447AB0E859'); + $customer->getColumn('name')->setLength(255); $project = $schema->getTable('kimai2_projects'); $project->dropIndex('IDX_407F12069395C3F37AB0E8595E237E06'); $project->dropIndex('IDX_407F12069395C3F37AB0E859BF396750'); + $project->getColumn('name')->setLength(255); $timesheet = $schema->getTable('kimai2_timesheet'); $timesheet->dropIndex('IDX_4F60C6B18D93D649502DF587'); diff --git a/src/Migrations/Version20190813162649.php b/src/Migrations/Version20190813162649.php new file mode 100644 index 00000000..7fb3b955 --- /dev/null +++ b/src/Migrations/Version20190813162649.php @@ -0,0 +1,78 @@ +isPlatformSqlite()) { + // does fail if we use transactions, as tables are re-created and foreign keys would fail + return false; + } + + return true; + } + + public function up(Schema $schema): void + { + $activity = $schema->getTable('kimai2_activities'); + $name = $activity->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } + + $project = $schema->getTable('kimai2_projects'); + $name = $project->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } + + $customer = $schema->getTable('kimai2_customers'); + $name = $customer->getColumn('name'); + if ($name->getLength() !== 150) { + $name->setLength(150); + } + $customer->getColumn('timezone')->setLength(64); + } + + public function down(Schema $schema): void + { + $activity = $schema->getTable('kimai2_activities'); + $activity->getColumn('name')->setLength(255); + + $project = $schema->getTable('kimai2_projects'); + $project->getColumn('name')->setLength(255); + + $customer = $schema->getTable('kimai2_customers'); + $customer->getColumn('name')->setLength(255); + $customer->getColumn('timezone')->setLength(255); + } +} diff --git a/var/data/kimai_test.sqlite b/var/data/kimai_test.sqlite index 4ac08c64f9a50a10b912ba8f38ae556033f8c219..b7c34096dfd1294e09da0e226fc3c8ae70fb0988 100644 GIT binary patch delta 1270 zcma)+T}&KR6vyY>duL~6XLn`?m|4CGOQCF*W!YVjm0d%M^&`=0!K6m*LrDWPV#7yZ zC6;2?Q6tuv6tbo#vDMa~C9$!opq&_v)|AA=Pae>RY7nCoqS2C=XcLfn7ax#5d6WOm zxp&U*Wb!{}CX+d@X#o38I(=4T7`6by8`dVj<#R;_d7uR!T2;AMxgSPJ61=BWjuZ zlzWGASSglYk$1qX6AO@+fjxWJW_Xt$&SVcLMfiI@7^p?bt2kc>`?0W+_()?6Z3&8; z^A$uS&PWyc8Z_-Q;dEmJY@@rkv+F7RBuENyGDwCo`7`|+e_NstU}A|n&Yo)&05_KD zgKoQNMDiz-@QjL!Wnf`!nTq)MGCj%C$0R@Q3lPicS)m^RUaTZv@Y#a|wpNqNw|G81 zCkGrk12R5(XWld+MP*w=#pLk11;u#X1R3v%kbHbP zmsV?ZH$n*^L(>{AqK9&-Y|4NvO|xY*q4y!!Xv0cP`Na)a%Hx z>>EmKhHYa3&{EbAA!TwD^D%%yO-9oDa|xBdgm&{ahM delta 12510 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