Upgrade Guide
=================

# Ginger v2.*

Since Ginger `v2.*` the bundle makes it possible to extend its abstract [tag-entity](#)
from your own symfony application.
 
Please note that - altough this is possible - you´re not forced to do so.

If you are happy with the abstract entity shipped by the bundle, the [basic tag-entity](#) will be used as concrete class by default. 


### CAUTION!

**If you want to upgrade the bundle to `v2.*` from within a symfony application that already has real data at it´s disposal, be aware that you will have to migrate some of your database tables!**


### ATTENTION!

When making changes to the database of a production system, **ALWAYS BE SURE TO HAVE A BACKUP OF YOUR DATABASE** before proceeding
with the following steps!!!

## So how do i upgrade my application?

Follow the steps below to upgrade to GingerBundle from v1 to v2 for any application that already 
has real data at it´s disposal.

#### Step 1: Remove references to the bundles legacy tag entity (crucial)

The new feature of extendable tags is a breaking change and not backwards compatible. 

You have to make sure to **remove all references** to the legacy tag entity of the GingerBundle from your application code **where it is necessary**.

To do this:

* Replace all occurrences of `DWGingerBundle:Tag` with `Tag::class` (also see the official [PHP docs](http://php.net/manual/en/migration55.new-features.php#migration55.new-features.class-name)) 
* In all places where it is necessary, update your use-statements accordingly (use `Your\Qualified\Classname | DW\GingerBundle\Entity\BaseTag` instead of `DWGingerBundle:Tag`)
* Tip: You may also use the [TagManager](https://bitbucket.org/dwerk/dwgingerbundle/src/feature-extendable-tags/Doctrine/TagManager.php) to create or update tags, retrieve the tag repository or get the FQCN of the concrete tag class that is in use.
  
  Examples:
  
```php

// Create a new tag
$tag = $this->tagManager->createObject();

// Set some attribute and persist or update the tag
$tag->setTitle('my-new-tag');				
$this->tagManager->updateObject($tag);

// Get the tag repository.
$tagRepo = $this->tagManager->getRepository();

// Get the fully qualified class name of the tag entity in use.
$fqcn = $htis->tagManager->getClass();

``` 
  
#### Step 2: Migrate the log table (crucial)

Whether you´re extending the bundle´s tag-entity from within your symfony application or not, **in each case** you will have to 
migrate the log-table (`ginger_ext_log_entry`) of your existing database. 

**NOTE:** If you miss that, you will get wrong and inconsistent results when filtering the person-list by tags. Also the logging
of activities in general may not behave as expected.

To migrate the log-table you need to replace the fully qualified class name of the tag-entity used in Ginger v1 (which is `DW\GingerBundle\Entity\Tag`) with the
the one you are using. 

This could be one of the following:

* `DW\GingerBundle\Entity\BaseTag`: If you are **NOT EXTENDING** the tag-entity from within your symfony application
* The FQCN of your extended entity (e.g: `App\Entity\MyTag`): If you **ARE EXTENDING** the tag-entity from within your symfony application

To migrate the log table, you need to update the values of the columns `collection_item_class` and `object_class` for each row
where the value equals to the value `DW\\GingerBundle\\Entity\\Tag` accordingly.


**Example Queries (tested on Sequel Pro 1.1.2):**

**Note:** The example below assumes that you have not extended the tag entity from within your application and are using the bundles default tag entity (`DW\GingerBundle\Entity\BaseTag`).

```sql

UPDATE ginger_ext_log_entry
SET collection_item_class = 'DW\\GingerBundle\\Entity\\BaseTag'
WHERE collection_item_class = 'DW\\GingerBundle\\Entity\\Tag';

```

```sql

UPDATE ginger_ext_log_entry
SET object_class = 'DW\\GingerBundle\\Entity\\BaseTag'
WHERE object_class = 'DW\\GingerBundle\\Entity\\Tag';

```

#### Step 3: Migrate the tag table (optional)

If you extended the tag entity from within your symfony application, in addition to `Step 1` and `Step 2` above you
will have to migrate your tag-table (`ginger_tag`) as well.

**Let´s say...**
 
 ...you have extended the bundle´s abstract tag-entity from like the following with an entity `App\Entity\MyTag` like the following:

* **Bundle configuration:**

```yaml

# config/packages/dw_ginger.yaml

dw_ginger:
  crud:
    person:
      class: App\Entity\MyPerson
      form:
        type: App\Form\MyPersonType
        name: "app_edit_myperson"
    tag:
      class: App\Entity\MyTag
      form:
        type: App\Form\MyTagType
        name: "app_edit_mytag"

	
	# more of your config...

```

* **Doctrine configuration:**

```yaml

# config/packages/doctrine.yaml
	
	# some of your config...
	
    orm:
    	# more of your config...
        
        resolve_target_entities:
            DW\GingerBundle\Entity\PersonInterface: App\Entity\MyPerson
            DW\GingerBundle\Entity\TagInterface: App\Entity\MyTag

```


* **Entity configuration:**

```php

// src/Entity/MyTag

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use DW\GingerBundle\Entity\Tag as AbstractTag;

/**
 * @ORM\Entity()
 * @ORM\Table(name="app_my_tag")
 */
class MyTag extends AbstractTag
{
	// Some additional fields or relations...
    
    public function __construct()
    {
        parent::__construct();
        
        // your custom stuff...
        
    }
    
    // ...

``` 

##### 3.1 Update your DB schema

Now update your DB-schema (for the sake of simplicity, doctrine-migrations are not used in the example below):

```

php bin/console doctrine:schema:update --force

```

This will result in an error like the following:
```

Updating database schema...


In AbstractMySQLDriver.php line 68:

  An exception occurred while executing 'ALTER TABLE ginger_persons_tags ADD CONSTRAINT FK_D35D44D0BAD26311 FOREIGN KEY (tag_id) REFERENCES app_my_tag (id)':

  SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`ginger_v2_test`.`#sql-287_3cb`, CONSTRAINT `FK_D35D44D0BAD26311` FOREIGN KEY (`tag_id`) R
  EFERENCES `app_my_tag` (`id`))


In PDOConnection.php line 109:

  SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`ginger_v2_test`.`#sql-287_3cb`, CONSTRAINT `FK_D35D44D0BAD26311` FOREIGN KEY (`tag_id`) R
  EFERENCES `app_my_tag` (`id`))


In PDOConnection.php line 107:

  SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`ginger_v2_test`.`#sql-287_3cb`, CONSTRAINT `FK_D35D44D0BAD26311` FOREIGN KEY (`tag_id`) R
  EFERENCES `app_my_tag` (`id`))

```

If you check your database, in spite of the error above a table named `app_my_tag` with the correct structure should have been created.

##### 3.2 Migrate your exitsting tags-table

* Make an sql-dump of your existing tag-table (normally should be named `ginger_tag`)
* Delete the legacy tag-table (normally should be named `ginger_tag`)
* Import your dumped tag-data into your newly created tag-table (`app_my_tag` in case of the example configuration above). Note that you will have to adjust the dumped sql-file to fit your needs!
* Update your DB schema

#### Step 4: Create a mapping table for enriching austrian addresses (mandatory)
Austrian addresses with a postcode will be enriched with city name and the associated persons will be taggged with district and state tags.
To do so there must exist a table with the mapping data. Since this table is accessed directly (w/o entity) it needs to be created manually. To do so import the SLQ-Dump into your database.
Table dump is in file `ginger_plz_austria.sql.gz`