Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question/Bug] Issues adding a new property to an existing Core Entity #300

Closed
Allex1337 opened this issue Feb 7, 2018 · 8 comments
Closed
Labels

Comments

@Allex1337
Copy link

Allex1337 commented Feb 7, 2018

Hey guys!

I have tried endlessly to add a property to a Core Entity and have it displayed in the data grid and nothing is working.

I have tried of course to follow all the steps from the documentation as well as many other things that passed through my mind and nothing seems to work.

Let me give you the following example:

  • Scenario: Let's say I would want to add a column with the name area_name to the Core Entity Oro\Bundle\ContactBundle\Entity\ContactAddress

To achieve this, I have the following:

  • I have overwrote the ContactBundle (in which the ContactAddress belongs):

src/ContactBundle/ContactBundle.php

<?php

namespace ContactBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class ContactBundle extends Bundle
{
    public function getParent()
    {
        return 'OroContactBundle';
    }
}
  • I have created the local ContactAddress entity which extends the ExtendEntity*:

src/ContactBundle/Entity/ContactAddress.php

<?php

namespace ContactBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use ContactBundle\Model\ExtendContactAddress;
use Oro\Bundle\EntityConfigBundle\Metadata\Annotation\Config;

/**
 * @ORM\Entity()
 * @ORM\Table("orocrm_contact_address")
 * @Config()
 */
class ContactAddress extends ExtendContactAddress
{
}

src/ContactBundle/Model/ExtendContactAddress.php

<?php

namespace ContactBundle\Model;

use Oro\Bundle\ContactBundle\Entity\ContactAddress;

class ExtendContactAddress extends ContactAddress
{
    public function getAreaName()
    {
    }

    /**
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @param null|string $areaName
     */
    public function setAreaName($areaName)
    {
    }
}

*As a kind note - my ExtendContactAddress entity also extends the Core ContactAddress entity - I know this makes sense else it would be viewed as a standalone entity and not as an overwritten one, even though the documentation skips this part

  • I have created a migration script to add the new desired column:

src/ContactBundle/Migrations/Schema/v1_0/AddAreaNameToContactAddress.php

<?php

namespace ContactBundle\Migrations\Schema\v1_0;

use Doctrine\DBAL\Schema\Schema;
use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope;
use Oro\Bundle\MigrationBundle\Migration\Migration;
use Oro\Bundle\MigrationBundle\Migration\QueryBag;

class AddAreaNameToContactAddress implements Migration
{
    /**
     * @param Schema $schema
     * @param QueryBag $queries
     * @throws \Doctrine\DBAL\Schema\SchemaException
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function up(Schema $schema, QueryBag $queries)
    {
        $table = $schema->getTable('orocrm_contact_address');
        $table->addColumn('area_name', 'string', [
            'oro_options' => [
                'extend'   => ['owner' => ExtendScope::OWNER_CUSTOM],
                'datagrid' => ['is_visible' => true],
                'form'     => ['is_enabled' => true],
                'view'     => ['is_displayable' => true],
                'merge'    => ['display' => true],
            ]
        ]);
    }
}
  • Then I have added the new column in the datagrids.yml to have it displayed in the Contacts tab in the UI:

src/ContactBundle/Resources/config/oro/datagrids.yml

datagrids:
    custom-contacts-grid:
        extends: contacts-grid

        source:
            type: orm
            query:
                select:
                    - address.area_name as area_name

        columns:
            area_name:
                label: Region Area Name
                data_name: area_name
  • And of course, as a kind mention, I have also enabled the bundle the Oro way:

src/ContactBundle/Resources/config/oro/bundles.yml

bundles:
    - ContactBundle\ContactBundle
  • After this:
  1. I have run the migrations command which completed with no issues (oro:migration:load) and also has shown that my bundle was loaded properly.
  2. I cleared the cache in the following ways:
  • rm -rf app/cache/*
  • cache:clear
  • oro:entity-config:cache:clear (and oro:entity-config:update)
  • oro:entity-extend:cache:clear
  • also restarted apache
  1. I checked the new column in the database table orocrm_contact_address and it is shown properly
  2. I checked table oro_entity_config, decode64 the data field of my Class and the field was there
  3. I checked table oro_entity_config_fields and the field is there

But when I try to load the Contacts tab in the UI, it says "No records found" and in the Network console tab, the XHR request responded with:

[Semantical Error] line 0, col 749 near 'area_name as': Error: Class Oro\Bundle\ContactBundle\Entity\ContactAddress has no field or association named area_name

No matter what I tried I end up with the same error. I cant get it shown in the UI.
I have also tried to overwrite the parameter oro_contact.contact_address.entity.class with my class (both via app/config/config.yml and even via a CompilerPass) and I cant seem to overcome this error.

Can you please explain what am I missing or if there is an issue?
Thanks a lot in advance!

@vsoroka
Copy link
Contributor

vsoroka commented Feb 8, 2018

Hello @Allex1337

You did almost all right, except overriding the entity. Also steps with running oro:entity-config:cache:clear and oro:entity-extend:cache:clear are redundant.

Here are correct steps:

  1. create the bundle
  2. add Resources/config/oro/bundles.yml
  3. add the migration
  4. remove the cache, rm -rf app/cache/*
  5. run cache:clear
  6. run oro:migration:load --force (also you can run oro:migration:load --dry-run before this comand to make sure that your migration will be executed)

That is all, after that you can do other changes, like creation datagrid.

@Allex1337
Copy link
Author

Allex1337 commented Feb 8, 2018

Hey @vsoroka,

Thank you for your answer.

Please read carefully all the steps from my post.
I already did all the steps you mentioned and I have no problem with them, as everything you mentioned seems to work fine, but after doing this (exactly the same steps you mentioned, in the exact same order, and of course verifying before and after this, not only with --dry-run, but also in the oro_entiy_config and oro_entity_config_fields and the orocrm_contact_address itself after the command ran) and configuring the datagrids.yml as shown above, I have the mentioned error.

Please look again at the steps followed by me and the outcome.
I can also upload the bundle if you want to try it out yourself. Let me know if you need any other info as well.
Looking forward for your answer.

@vsoroka
Copy link
Contributor

vsoroka commented Feb 8, 2018

@Allex1337

I've tried your grid in the following way:

  • add it for datagrids.yml
  • replace contacts-grid to custom-contacts-grid in Oro/Bundle/ContactBundle/Resources/views/Contact/index.html.twig
    after that I see REGION AREA NAME columns on contacts grid.

Could you please check it one more time? In case if it will not work, please upload your bundle, I will take a look at it.

@Allex1337
Copy link
Author

Allex1337 commented Feb 8, 2018

Hey @vsoroka,

It seems to be working now but only without creating the entity and the extend entity (without having my own empty src/ContactBundle/Entity/ContactAddress.php & the one which is extended src/ContactBundle/Model/ExtendContactAddress.php with setters and getters for the new property) but this is the way it supposed to work?
You should only have just the migration file when adding a new property to a core entity and no entity with the same name as the one extended which should extend the Extend one which has the getters and setters?
If yes, then how can I create a new instance of the ContactAddress let's say somewhere in a controller or service, because something like

$contactAddress = new Oro\Bundle\ContactBundle\Entity\ContactAddress();
$contactAddress->setAreaName('demo');

cannot work (I've put the full namespace on purpose to ensure that we are referring to the core entity, since I do no longer have the empty entity and the one with the getters and setters)?
Also how can I ever retrieve the entity and getAreaName() on it?
Also the IDE?

All the documentation is seriously confusing on this point.
In the documentation, there is an empty entity class in the AppBundle with the same name as the one to which the new property is added, which extends an Extend one which has the empty getters and setters for the new property to assist the IDE, but having those apparently breaks everything.

Also, as a second note with lower priority, I had to override the bundle and copied the entire contents of Oro/Bundle/ContactBundle/Resources/views/Contact/index.html.twig to my src/ContactBundle/Resources/views/Contact/index.html.twig and changed the gridName for this to work. Is this the only method to set the new gridName properly? Is it possible to change only the gridName to not have to copy the entire contents of the index.html.twig file?

Please clarify.
Thanks in advance.

@vsoroka
Copy link
Contributor

vsoroka commented Feb 8, 2018

@Allex1337

Yes, to add new field you just need to create a migration.
The getters and setters will be generated automatically. You can find them in /app/cache/dev/oro_entities/Extend/Entity/EX_OroContactBundle_ContactAddress.php
Unfortunately the drawback of this approach is that there is no autocomplete in IDE for such fields.

About adding your column on the contact grid. There are two solutions. The first one is to copy TWIG template and change grid name there. The second solution is to create an event listener for existing contact grid and add your column there. Here is an example of such listener:

<?php

namespace Oro\Bridge\ContactUs\EventListener;

use Oro\Bundle\DataGridBundle\Event\BuildBefore;

class ContactRequestDatagridListener
{
    /**
     * @param BuildBefore $event
     */
    public function onBuildBefore(BuildBefore $event)
    {
        $config = $event->getConfig();

        $config->addColumn(
            'customerUserName',
            ['label' => 'oro.contactus.contactrequest.customer_user.label'],
            'customerUser.firstName as customerUserName',
            ['data_name' => 'customerUserName'],
            [
                'type' => 'string',
                'data_name' => 'customerUserName'
            ]
        );

        $query = $config->getOrmQuery();
        $query->addLeftJoin($query->getRootAlias().'.customer_user', 'customerUser');
    }
}

to register the listener use oro_datagrid.datagrid.build.before.contacts-grid tag in services.yml:

    oro_contact_us_bridge.event_listener.contact_request_datagrid:
        class: 'Oro\Bridge\ContactUs\EventListener\ContactRequestDatagridListener'
        tags:
            - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.contacts-grid, method: onBuildBefore }

@Allex1337
Copy link
Author

Hey @vsoroka,

Thanks again for the answer.

But then how can I make a new instance of the ContactAddress class and set or get the new property somewhere in a service or controller if I would want to?
Something like this

$contactAddress = new Oro\Bundle\ContactBundle\Entity\ContactAddress();
$contactAddress->setAreaName('demo');

can no longer work.

Should I retrieve somehow the entity differently or? A new instance of the cached entity is not wise and is also abstract by design.

Looking forward for your answer.

@vsoroka
Copy link
Contributor

vsoroka commented Feb 9, 2018

@Allex1337

Your code will work fine. There is no difference for creation a regular and extendable entity because the autogenerated class is a superclass for extendable entity.
I understand that it is a bit confusing, because in code you see that ContactAdderss extends ExtendContactAddress, but actually ContactAdderss extends EX_OroContactBundle_ContactAddress. This happens because we use class_alias function to substitute ExtendContactAddress with EX_OroContactBundle_ContactAddress. If you are interesting in more details, you can take a look at OroEntityExtendBundle.php, pay attention on ensureAliasesSet method.

@Allex1337
Copy link
Author

Everything is clear now, thanks a lot for clarifications!

All the best!
Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants