Dependent instances in one list - instance

I have a problem in code design. I try to read some files and create for every file one or more instances (dependin on the content). But some instances depend on other files in the list, so that every instance has to know the top class. Following example should illustrate what I mean:
class SetOfAll(object)
def __init__(self):
self.matrjoschkas = []
def add(self, matrjoschka):
self.matrjoschkas.append(matrjoschka)
def create_matrjoschkas(self):
for file in glob.glob('*.txt'):
self.add(Matrjoschka(file, self))
class Matrjoschka(object)
def __init__(self, file, container):
self._container = container
...
if some condition:
self._container.add(Matrjoschka(..., self._container))
Is there an elegant way to avoid, that every instance has to know the top class? Because in my case it's a little bit more complicated and it would be good if some factory could do it.

Well, there are certainly many ways of doing this, but from what I can see you just need a way to explicitly state the dependencies between files. You could then ask a factory to create a list of files based on the file's source and the configured dependencies.
Pseudo-code:
filesFactory = new FilesFactory({
file1: ['file2', 'file3'] //file1 depends on file2 and file3
});
filesSource = new GlobFilesSource('*.txt'); //FilesSource could be an abstraction and GlobFilesSource a concrete implementation
allFiles = filesFactory.resolveAllFilesFrom(filesSource); // ['file1', 'file2', 'file3']
If the dependency conditions are more complex than a simple id matching then you could just configure predicates. Here's a pseudo-code sample using a predicate to achieve the same dependency configuration as above:
[
{
predicate: function (currentFiles) {
return currentFiles.contains('file1');
},
files: ['file2', 'file3']
}
]
This design is much more flexible than yours because not only the Matrjoschka class doesn't have to know about it's container, but it also doesn't have to know about dependency rules.

Related

What is the proper way to extend a Fixture with a Parameter Interface and add new parameters of a different type?

Let's assume I have a test fixture that inherits from ::testing::WithParamInterface<MyType> that uses it in SetUp().
class MyFixture : ..., ::testing::test, ::testing::WithParamInterface<MyType> {
virtual void SetUp() override {
auto param = GetParam();
...
}
};
I wish to write a text fixture that subclasses this, however will provide a param interface in addition to the one the current fixture provides. i.e. something like:
class SubclassedFixture : ..., MyFixture, ::testing::WithParamInterface<MySecondType> { ... };
Ideally this would then run all tests in MyFixture with the types specified in INSTANTIATE_TEST_CASE_P(..., MyFixture, {MyFixtureSpecifiedValues}). And then run all the tests in SubclassedFixture over the combinations INSTANTIATE_TEST_CASE_P(..., SubclassedFixture, {MyFixtureSpecifiedValues} x {SubclassedFixtureValues}).
A secondary goal here is to change as little code as possible in the already existing MyFixture class.
I do not expect anything in Google Test to neatly support this. However what would be the best way to restructure these tests to get this functionality, changing MyFixture at little as possible?

Wagtail: Extend page model

I have created in the past multiple pages for Wagtail.
Example:
class PlainPage(Page):
body = StreamField(BasicStreamBlock, null=True, blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
Now I would like to an extend all this pages by giving them the possibility to set them to no-index.
For this reason I would like to add a boolean field to the promote_panel.
What would be the best way adding this feature to all pages I have already created?
no_index = models.BooleanField(default=False)
promote_panels = Page.promote_panels + [
FieldPanel('no_index'),
]
What would be the correct Wagtail way, to extend all my Page classes with this code?
Using Django's Class Mixins, it is possible to add fields to all existing models without too much hassle.
1. Create a Mixin
First - create a new CustomPageMixin (name this whatever you want) that extends the Page model and has the meta abstract=True set.
class CustomPageMixin(Page):
class Meta:
abstract=True
no_index = models.BooleanField(default=False)
# adding to content_panels on other pages will need to use THIS promote_panels
# e.g. promote_panels = CustomPageMixin.promote_panels + [...]
promote_panels = Page.promote_panels + [
FieldPanel('no_index'),
]
2. Update ALL existing page models
Update all your models in use to use the mixin, instead of extending the Page class, they will actually extend your mixin directly.
from ... import CustomPageMixin
class StandardPage(CustomPageMixin):
#...
class HomePage(CustomPageMixin):
#...
3. Run Migrations
Note: This will add the no_index field to ALL pages that now extend your new mixin.
./manage.py makemigrations
./manage.py migrate
Potential Issues with this approach
This may not be the best way to do this, as it is a bit indirect and hard to understand at first glance.
This does not actually change the Page model fields, so it will only be available when you access the actual specific models' instance via Page.specific
It will be a bit more tricky to use this for special Page types such as AbstractEmailForm.

How to get all FAL File Objects which are referenced?

I'm trying to make a extbase extension for TYPO3 to get alle file objects with mimetype image/... which referenced by any content, plugin or fluid in typo3.
But i don't know which is the best way to get these data. How should i create a model in my extension and how should i create the correct repository?
If i create a custom query i'm not sure how to return a complete FAL Object which contains any data (like metadata) etc.
hope someone could help me to find the right way, and maybe has a example or something.
thanks a lot
You could do it like this, details are at the bottom:
Get all file references.
Go through them, retrieve the referenced file for each of them and retain only the ones where the field mime_type starts with image/.
There are two things you probably need to watch out for:
The field mime_type needs to be up to date. Check the FAL scheduler indexing task for that.
Performance. Depending on the number of files you have, it could be much faster to do this with a custom SQL statement which makes use of a JOIN. But you should only do that if performance is a problem.
How to get all file references:
First, build your own empty file reference class:
namespace Vendor/Extkey/Domain/Model;
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {}
Make sure to configure it in your TypoScript to be serialized to the table sys_file_reference:
config.tx_extbase.persistence {
classes {
Vendor\Extkey\Domain\Model\FileReference {
mapping {
tableName = sys_file_reference
}
}
}
}
Add a repository for the references:
namespace Vendor/Extkey/Domain/Repository;
class FileReferenceRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
public function initializeObject() {
/** #var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface */
$defaultQuerySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\QuerySettingsInterface');
$defaultQuerySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($defaultQuerySettings);
}
}
The reference class can be empty, but the repository needs it to be there in order to work correctly. Make sure you add the default query settings to ignore the page id, so you get all non-hidden and non-deleted file references by calling $fileReferenceRepository->findAll().
How to check the MIME-type of each referenced file:
You can get the MIME-type of each reference by calling
$fileReference->getOriginalResource()->getMimeType()
This should automatically fetch the original file from storage and read its MIME-type.

Yii dependency injection basic

Can anyone explain me DI basics please? I understand what it is, but I don't really know now, how to use DI container in practice. For example, I have 2 functions in the same controller:
public function actionIndex()
{
$productsModel = new Products();
$productsFormModel = new ProductsForm();
$informationFormModel = new InformationForm();
....
}
public function actionInformation()
{
$productsModel = new Products();
$productsFormModel = new ProductsForm();
$informationFormModel = new InformationForm();
....
}
So my two questions is:
As you see above, I use same models in these functions. It is good idea to initialized them into "public function init() {}" and then use them in all class globally or this is bad idea?
I think it should be better if these models would be injected into this controller, right? How to do it correctly?
I was created file DI.php, which I included into entry script. File content was:
<?php
\Yii::$container->set('products_model', 'app\models\Products');
\Yii::$container->set('products_form', 'app\models\ProductsForm');
\Yii::$container->set('information_form', 'app\models\InformationForm');
?>
So then I was able to get class app\models\Products instance globally (in every controller, view or model):
$instance_products = \Yii::$container->get('products_model');
$instance_products_form = \Yii::$container->get('products_form');
$instance_information_form = \Yii::$container->get('information_form');
But this is bad idea, right?
Please, answer someone my two questions. :)
Thanks!
Keeping things DRY is always a good idea. The classes seem very related, so I suggest making this relationship explicit by creating a new model (e.g. ProductsInfo). One could name the controller accordingly (ProductsInfoController), thereby clarifying the application structure.
Use dependency injection sparingly. If there is a different way way, use that instead. DI isn't a good fit for the described use-case.

Django REST framework flat, read-write serializer

In Django REST framework, what is involved in creating a flat, read-write serializer representation? The docs refer to a 'flat representation' (end of the section http://django-rest-framework.org/api-guide/serializers.html#dealing-with-nested-objects) but don't offer examples or anything beyond a suggestion to use a RelatedField subclass.
For instance, how to provide a flat representation of the User and UserProfile relationship, below?
# Model
class UserProfile(models.Model):
user = models.OneToOneField(User)
favourite_number = models.IntegerField()
# Serializer
class UserProfileSerializer(serializers.ModelSerializer):
email = serialisers.EmailField(source='user.email')
class Meta:
model = UserProfile
fields = ['id', 'favourite_number', 'email',]
The above UserProfileSerializer doesn't allow writing to the email field, but I hope it expresses the intention sufficiently well. So, how should a 'flat' read-write serializer be constructed to allow a writable email attribute on the UserProfileSerializer? Is it at all possible to do this when subclassing ModelSerializer?
Thanks.
Looking at the Django REST framework (DRF) source I settled on the view that a DRF serializer is strongly tied to an accompanying Model for unserializing purposes. Field's source param make this less so for serializing purposes.
With that in mind, and viewing serializers as encapsulating validation and save behaviour (in addition to their (un)serializing behaviour) I used two serializers: one for each of the User and UserProfile models:
class UserSerializer(serializer.ModelSerializer):
class Meta:
model = User
fields = ['email',]
class UserProfileSerializer(serializer.ModelSerializer):
email = serializers.EmailField(source='user.email')
class Meta:
model = UserProfile
fields = ['id', 'favourite_number', 'email',]
The source param on the EmailField handles the serialization case adequately (e.g. when servicing GET requests). For unserializing (e.g. when serivicing PUT requests) it is necessary to do a little work in the view, combining the validation and save behaviour of the two serializers:
class UserProfileRetrieveUpdate(generics.GenericAPIView):
def get(self, request, *args, **kwargs):
# Only UserProfileSerializer is required to serialize data since
# email is populated by the 'source' param on EmailField.
serializer = UserProfileSerializer(
instance=request.user.get_profile())
return Response(serializer.data)
def put(self, request, *args, **kwargs):
# Both UserSerializer and UserProfileSerializer are required
# in order to validate and save data on their associated models.
user_profile_serializer = UserProfileSerializer(
instance=request.user.get_profile(),
data=request.DATA)
user_serializer = UserSerializer(
instance=request.user,
data=request.DATA)
if user_profile_serializer.is_valid() and user_serializer.is_valid():
user_profile_serializer.save()
user_serializer.save()
return Response(
user_profile_serializer.data, status=status.HTTP_200_OK)
# Combine errors from both serializers.
errors = dict()
errors.update(user_profile_serializer.errors)
errors.update(user_serializer.errors)
return Response(errors, status=status.HTTP_400_BAD_REQUEST)
First: better handling of nested writes is on it's way.
Second: The Serializer Relations docs say of both PrimaryKeyRelatedField and SlugRelatedField that "By default this field is read-write..." — so if your email field was unique (is it?) it might be you could use the SlugRelatedField and it would just work — I've not tried this yet (however).
Third: Instead I've used a plain Field subclass that uses the source="*" technique to accept the whole object. From there I manually pull the related field in to_native and return that — this is read-only. In order to write I've checked request.DATA in post_save and updated the related object there — This isn't automatic but it works.
So, Fourth: Looking at what you've already got, my approach (above) amounts to marking your email field as read-only and then implementing post_save to check for an email value and perform the update accordingly.
Although this does not strictly answer the question - I think it will solve your need. The issue may be more in the split of two models to represent one entity than an issue with DRF.
Since Django 1.5, you can make a custom user, if all you want is some method and extra fields but apart from that you are happy with the Django user, then all you need to do is:
class MyUser(AbstractBaseUser):
favourite_number = models.IntegerField()
and in settings: AUTH_USER_MODEL = 'myapp.myuser'
(And of course a db-migration, which could be made quite simple by using db_table option to point to your existing user table and just add the new columns there).
After that, you have the common case which DRF excels at.