In Model, when I have a hasMany relation, can I somehow get the values of a certain attribute concatenated? Is there something like that?
public function getRelatedManyAttribute() {
return $this->relatedMany->concat('attributeMany');
}
I am not entirely sure if I understood you cerrectly, but if you want all the values of the same attribute of a 1:n-relation it could be this simple oneliner:
public function getIdsConcatenated() {
return implode(', ', ArrayHelper::getColumn($this->myManyRelation, 'id'));
}
I think you are looking for this -
public function getSubMenuMenu()
{
return $this->hasMany(Your_table_name::className(), ['id' => 'your_column_name']);;
}
for more understanding visit this link
Related
I've been struggling with this for a few days now, and I'm still not clear on the correct approach. I've seen many examples online, but each one does it differently. The options I see are:
Pass only primitive values
Pass the complete model
Pass new instances of value objects that refer to changes in the domain/model
Create a specific DTO/object for each event with the data.
This is what I am currently doing, but it doesn't convince me. The example is in PHP, but I think it's perfectly understandable.
MyModel.php
class MyModel {
//...
private MediaId $id;
private Thumbnails $thumbnails;
private File $file;
//...
public function delete(): void
{
$this->record(
new MediaDeleted(
$this->id->asString(),
[
'name' => $this->file->name(),
'thumbnails' => $this->thumbnails->toArray(),
]
)
);
}
}
MediaDeleted.php
final class MediaDeleted extends AbstractDomainEvent
{
public function name(): string
{
return $this->payload()['name'];
}
/**
* #return array<ThumbnailArray>
*/
public function thumbnails(): array
{
return $this->payload()['thumbnails'];
}
}
As you can see, I am passing the ID as a string, the filename as a string, and an array of the Thumbnail value object's properties to the MediaDeleted event.
How do you see it? What type of data is preferable to pass to domain events?
Updated
The answer of #pgorecki has convinced me, so I will put an example to confirm if this way is correct, in order not to change too much.
It would now look like this.
public function delete(): void
{
$this->record(
new MediaDeleted(
$this->id,
new MediaDeletedEventPayload($this->file->copy(), $this->thumbnail->copy())
)
);
}
I'll explain a bit:
The ID of the aggregate is still outside the DTO, because MediaDeleted extends an abstract class that needs the ID parameter, so now the only thing I'm changing is the $payload array for the MediaDeletedEventPayload DTO, to this DTO I'm passing a copy of the value objects related to the change in the domain, in this way I'm passing objects in a reliable way and not having strange behaviours if I pass the same instance.
What do you think about it?
A domain event is simply a data-holding structure or class (DTO), with all the information related to what just happened in the domain, and no logic. So I'd say Create a specific DTO/object for each event with the data. is the best choice. Why don't you start with the less is more approach? - think about the consumers of the event, and what data might they need.
Also, being able to serialize and deserialize the event objects is a good practice, since you could want to send them via a message broker (although this relates more to integration events than domain events).
I am following the advanced developer tutorial (https://docs.shopware.com/en/shopware-platform-dev-en/how-to/indepth-guide-bundle).
Currently I'm at step 7, and according to the tutorial what I've made so far should work.
But it doesn't.
In the database it shows the association, but I can't retrieve them from the repository.
You have to add the association to the Criteria.
$criteria->addAssociation("name_of_association")
Without it, the associations come as null.
Okay, turns out I switched up two parameters by accident. When I set them correctly it worked as it should.
<?php declare(strict_types=1);
namespace Swag\BundleExample\Core\Content\Product;
use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\EntityExtension;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Inherited;
use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToManyAssociationField;
use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;
use Swag\BundleExample\Core\Content\Bundle\Aggregate\BundleProduct\BundleProductDefinition;
use Swag\BundleExample\Core\Content\Bundle\BundleDefinition;
class ProductExtension extends EntityExtension
{
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new ManyToManyAssociationField(
'bundles',
BundleDefinition::class,
BundleProductDefinition::class,
'product_id',
'bundle_id'
))->addFlags(new Inherited())
);
}
public function getDefinitionClass(): string
{
return ProductDefinition::class;
}
}
I'm talking about the 'product_id' and 'bundle_id'. In my case I had the 'product_id' as the last parameter.
I'm trying to write a custom validator that will check if an entity exists in the database, using OrmLite. The problem is that the type arguments for IRuleBuilder can no longer be inferred from usage.
I have to write the method call like this:
RuleFor(r => r.Id).Exists<DtoName, int, EntityName>()
But I want to write it like this:
Rulefor(r => r.Id).Exists<EntityName>()
This happens because IRuleBuilder has two type parameters and the method is an extension method. Is there a smart, fluent way to design this and make the function call preferably like the second version?
Here is code for my extension method and my validator:
public static class AbstractValidatorExtensions
{
public static IRuleBuilderOptions<T, TProperty> Exists<T, TProperty, U>(this IRuleBuilder<T, TProperty> ruleBuilder)
{
return ruleBuilder.SetValidator(new EntityExistsValidator<U>());
}
}
public class EntityExistsValidator<T> : PropertyValidator
{
public EntityExistsValidator() : base("Entity does not exist") {}
protected override bool IsValid(PropertyValidatorContext context)
{
return HostContext.Resolve<Repository>()
.Exists<T>((int)context.PropertyValue);
}
}
My experience with FluentValidation is that you’re trying to push more and more logic into validators. I would not do this as it adds too much complexity. My rule of thumb is to validate discrete property values only. Example: I would just use FluentValidation to check if property int Id is 0 or greater than 0. The check if the entity already exists I would move to another service (often called “the business logic”).
You'll need to a Custom Validator for custom validation to access dependencies, something like:
RuleFor(x => x.Id)
.Must(id =>
{
using (var db = HostContext.AppHost.GetDbConnection(base.Request))
{
return !db.Exists<EntityName>(x => x.Id == id);
}
})
.WithErrorCode("AlreadyExists")
.WithMessage("...");
I'd also consider just doing validation that use dependencies in your Services instead:
if (Db.Exists<EntityName>(x => x.Id == request.Id))
throw new ArgumentException("Already Exists", nameof(request.Id));
I have list of domain objects which each one of them need to be called as follows:
(<DOMAIN CLASS>.withCriteria {
dataSecurityGroups {
'in' 'id', entitiesIds as Long[]
}
})
The idea is to have this code once, while changing the code a given parameter.
I know that there are several ways to implement it using groovy, and I tried to use them all.
I need to know what is the best practice and short way to do this.
Thanks!
You said you have a List of domain classes so the code below assumes that is true. You don't say what you want to do with the results of each of those queries, so I will assume you have that under control.
You could do something like this...
def listOfDomainClasses = // you have initialized this list somehow...
listOfDomainClasses.each { domainClass ->
def resultForThisClass = domainClass.withCriteria {
dataSecurityGroups {
'in' 'id', entitiesIds as Long[]
}
})
// do something with resultForThisClass
}
I hope that helps.
I'm assuming you are using Grails, since you tagged this question with Gorm. If so, try this:
Class clazz = grailsApplication.domainClasses.find { it.clazz.simpleName == "<DOMAINCLASS>" }.clazz
clazz.withCriteria {
dataSecurityGroups {
'in' 'id', entitiesIds as Long[]
}
}
Or replace grailsApplication.domainClasses and use your list of domain classes instead.
It is not clear what you are really trying to do but maybe what you want is to write a method like this...
/**
* #param someDomainClass A domain class
* #return the results of the query
*/
def myQueryMethod(Class someDomainClass) {
someDomainClass.withCriteria {
dataSecurityGroups {
'in' 'id', entitiesIds as Long[]
}
}
}
Then you can call that method and pass as an argument whatever domain class is appropriate.
Is that the sort of thing you are looking for?
I have an interesting need for an extension method on the IEumerable interface - the same thing as List.ConvertAll. This has been covered before here and I found one solution here. What I don't like about that solution is he builds a List to hold the converted objects and then returns it. I suspect LINQ wasn't available when he wrote his article, so my implementation is this:
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if (null == converter)
throw new ArgumentNullException("converter");
return from item in collection
select converter(item);
}
}
What I like better about this is I convert 'on the fly' without having to load the entire list of whatever TOutput's are. Note that I also changed the type of the delegate - from Converter to Func. The compilation is the same but I think it makes my intent clearer - I don't mean for this to be ONLY type conversion.
Which leads me to my question: In my repository layer I have a lot of queries that return lists of ID's - ID's of entities. I used to have several classes that 'converted' these ID's to entities in various ways. With this extension method I am able to boil all that down to code like this:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.ConvertAll<Part>(PartRepository.Find);
}
where the 'converter' is really the repository's Find-by-ID method. In my case, the 'converter' is potentially doing quite a bit. Does anyone see any problems with this approach?
The main issue I see with this approach is it's completely unnecessary.
Your ConvertAll method is nothing different than Enumerable.Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>), which is a standard LINQ operator. There's no reason to write an extension method for something that already is in the framework.
You can just do:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select<int,Part>(PartRepository.Find);
}
Note: your method would require <int,Part> as well to compile, unless PartRepository.Find only works on int, and only returns Part instances. If you want to avoid that, you can probably do:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select(i => PartRepository.Find<Part>(i)); // I'm assuming that fits your "Find" syntax...
}
Why not utilize the yield keyword (and only convert each item as it is needed)?
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>
(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if(null == converter)
throw new ArgumentNullException("converter");
foreach(T item in collection)
yield return converter(item);
}
}