What are the Slack Archives?

It’s a history of our time together in the Slack Community! There’s a ton of knowledge in here, so feel free to search through the archives for a possible answer to your question.

Because this space is not active, you won’t be able to create a new post or comment here. If you have a question or want to start a discussion about something, head over to our categories and pick one to post in! You can always refer back to a post from Slack Archives if needed; just copy the link to use it as a reference..

Hello, again confusion for attributes in spryker … There is the concept of localized attributes in s

UPWG9AYH2
UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

Hello,
again confusion for attributes in spryker …
There is the concept of localized attributes in spryker. For example i would have the “color” attribute and the corresponding values like “white”, “black” etc …
If i am on the PDP in a german locale, i expect “weiss”, “schwarz” … and on english locale “black”, “white” etc …
To have this values localized, there is a dedicated localized table, for product abstract. This is spy_product_abstract_localized_attributes in my case … so for each laguage theres a dedicated row … this works so far.
What i dont get is, that these values are obviously used to be saved on the quote and also will be used on further processing … thats a bit strange.
What i would expect is some kind of “technically” value which is the same for each language. For white this would be “value.white” for example but instead, the “translation” of the language is saved to the quote (when adding to cart). I assumed till now, that this “technically” key is saved in the non localized attributes table (which is spy_product_attribute in that case) and will be used when saved to the quote

What do I miss here?

Best

Comments

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    You can’t ensure that the attribute or the localization for an attribute is still there in lets say 10 years.
    That’s why by design each order item is a complete copy of the related product, including attributes, at the moment they were added to the order. Same goes for all other order related data like address, prices, etc.
    At least that was the main reason why we’ve implemented it that way in the early Spryker days ;)

    It’s not very likely that a customer who ordered in german will have the need to see the order in a different language. If this is a scenario you would like to support I guess it needs to be implemented in the project.

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    Hi Alberto, thanks for your reply.
    Unfortunately we have the requirement, that we want to add corresponding images based on the selected attributes. For that our idea was to fetch images based on the key of the selected attribute. For example “value.closed” there will be a “value.closed.jpg” that gets displayed beside the selected value. But since there is no key which is common for each language, we cant have a common scheme to provide something like this … any ideas how to provide such information like images along with the attributes keys/values?
    Best

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    Images for order items are stored in the spy_sales_order_item_metadata table.
    So if you already know during the place order which image should be shown there you could implement ItemTransformerStrategyPluginInterface to replace the item image with the one you want to use. At this point you should have access to the attributes of the item or can at least join them from the spy_product_attributes table.
    With this solution you would put the decision what image should be used to display in the order history to the place order step.

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    I think there is a misunderstanding. My question is not about placing orders and saving data to the order from the quote. Its about how to append additional infos to simple key/value attribute pairs in general … on PDP or on filters on the catalog page … example: when i have some attribute “color” with english translation “black” … and i want to add a path to an image that shows a black item … my idea was to simple make a convention that the value is the image name … so there would be a “black.jpg” … but since its just the translation, its not possible because in every other language, the key would be another … even if not, the translation could also be more complex like complete sentences which is also hard to use for a file name.
    So my question is more how to append additional information
    a) for the attribute key
    b) for the attribute value
    Or how to solve this in any other way

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer
    edited July 2021

    Sorry for the missunderstanding.
    As the product attributes are stored as JSON in the database they can look like what every you want (hope I got the question right this time).
    In fact we extended the attributes to store what we call attribute_definitions (e.g.:

    "attribute_definitions": {"M000034": {"order": 9999999, "display_name": "M000034","reference": "Einsatzbereich", "group": "FEATURES", "key": "M000034"} 
    

    ) alongside. Beside extending the product import to store the attributes as objects we had to extend the ProductConcreteStorageWriter and the according ProductReaders in Glue.

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    The attribute_definitions are a field beside the attributes which give meta information for each attribute.

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    Okay i understand, so its more some kind of extension rather than modify existing data structure. Important point since we also don’t want to modify the ootb behaviour to get in trouble with it

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    We have both as we needed to have multivalues. But yes the meta information for each attribute are an extension so we can make use of the default behaviors

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    “attribute_definitions”: {“M000034": {“order”: 9999999, “display_name”: “M000034”,“reference”: “Einsatzbereich”, “group”: “FEATURES”, “key”: “M000034”}

    But this is on the same lavel as the attributes, correct?
    So
    {
    "key1" : "value1"
    "key2" : "value2"

    "attribute_definitions": {"M000034": {"order": 9999999, "display_name":"M000034","reference": "Einsatzbereich", "group": "FEATURES", "key": "M000034"}
    }

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    Exactly

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    Key1 would be M000034 so we can match attribute and attribute_definition

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    Okay, but doesnt spryker ootb interpretes this attribute_definitions not just as another attribute which must be displayed?^^

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    So i guess theres some work more needed in frontend, attribute mapper etcetc

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer
    attributes: {
      "M000034": "some value"
    },
    attribute_definitions: { … }
    

    Is what we have in our storage, so they are separated to not break the ootb behavior

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    And yes we had to implement the frontend part as well to make use of the attribute definitions.
    As we already customized a lot there it was no big deal for us (e.g.: attributes can have multiple values, they are sorted, grouped, etc.)

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    okay but on spy_product table where they have to be on same level, it does not break anything so far?

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    Sorry for much questions, just want to estimate the effort to put in here a bit :P

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    However, thanks so far for sharing your insights 🙂 That helped me a lot

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    We store them in spy_product_abstract_localized_attributes.attribute_definitions as JSON (same on concrete level).
    They should be in an extra field, which will require you to adapt the ProductConcreteStorageWriter (same for abstract) to sync the attribute definitions in the storage as well.
    You could also have an attributes_definition field added to spy_product, but we decided against as we do not have any untranslated attribute.

    In terms of effort this took me around one week, including the import and the glue part to make use of the attribute definitions.
    But as I’m the one who implemented the product attributes in the Spryker core I was pretty much aware of all the little details, so it might take a little longer if you are unfamiliar with product attributes.

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet

    To put this in the extra column makes absolutely sense. Thanks a lot

  • UPWG9AYH2
    UPWG9AYH2 Posts: 509 🧑🏻‍🚀 - Cadet
    edited July 2021

    @UL6DGRULR i have one additional thought to this story … do you think it might work to only save a technical attribute value key to the normal non-localized table and deal on frontend with translations?
    So then you would have in the attributes map something like

    { “key.color”: “value.black”}

    Without any concrete translations
    And on frontend you just do something like

    attribute.value | trans

    Which will give you the correct translation if one is applicable. If not then you will have in worst case the technical representation of the value, but this will be okay.

    it would be basically the same as for the attribute key stuff

    This will solve our struggle dealing with translations when mapping back to concrete filenames

    I don’t know if this is though too naive or it will be a performance killer …

  • Alberto Reyer
    Alberto Reyer Posts: 690 🪐 - Explorer

    Would work, but will decrease the performance on the frontend as you need to translate each attribute value. So either you translate per attribute (e.g.: attribute.value|trans) which would add so many storage requests or you once collect all attribute values, load all related translations at once and do the translation one time, which would increase the memory usage. Depending on the amount of attribute values you have this can become a performance bottleneck.
    The idea is to have all data as much prepared as possible in the storage to gain the best possible performance.

    I strongly suggest to use the synchronize process to pre process as much as possible and write everything to the storage in such a manner that no additional “joins” are necessary on frontend side.