How to seed database once with multiple views for consistent data - ember-cli-mirage

I might be thinking about mock APIs incorrectly, but I figured it was worth asking.
I am trying to create an object with a basic view and a detailed view, for example "basic-author" and "detailed-author". But, I would like each object to return consistent data. For example, properties like "author_name" should be the same for basic-author and detailed-author.
I am currently trying to accomplish this by generating a list of authors and extending it:
// mirage/scenarios/default.js
server.createList('author', 20);
// mirage/config.js
this.get('/basic-author', (schema) => {
return schema.basicAuthors.all();
});
// mirage/factories/author.js
import { Factory, faker } from 'ember-cli-mirage';
export default Factory.extend({
// bunch of properties, like author_name
});
// mirage/factories/basic-author.js, mirage/factories/detailed-author.js
import Author from './author';
export default Author.extend({
});
But, obviously, this won't work because getting all basicAuthors returns nothing because there are no "basic-author" in the database. If I try to change the routes to return all authors, my ember models won't work because it is returning a list of 20 authors, which is the incorrect model type.
I have also tried setting the faker seed, but that makes every item the same.

The best way to accomplish this is to use Factory traits. Give the docs a read, then you should be able to set up something like this:
// mirage/factories/author.js
import { Factory, trait, faker } from 'ember-cli-mirage';
export default Factory.extend({
authorName() {
return faker.name.firstName();
},
age: 10,
withDetails: trait({
email() {
return `${this.authorName}#gmail.com`;
},
ssn: 123456789
})
});
Then in tests/dev you can create a basic authors like this
server.create('author');
server.createList('author', 20);
and detailed authors like this:
server.create('author', 'withDetails');
server.createList('author', 20, 'withDetails');

Related

How to Add a field in cascade of 2 many to one on Easyadmin 4 Symfony 6

I read and try a lots of things just to add a field witch is in relation.
One Dance have a level (beginner, improver...) and one Level have a Style (Country music, disco...). So for a dance I can get the level and associate style. Dance is MTO with Level, and Level is MTO with Style. It work fine in traditionnel controller and in Dance Index twig I can do
{{ dance.level.style }}
It's work fine.
Impossible for me to do that in EasyAdmin: In Danse Crud Controller
yield AssociationField::new('level');
is naturally working fine but how adding the style name? I'm not familiar with Queribuilder if it's the solution. I read Symfony Documentation easyadmin about unmapped fields but I don't undestand "createIndexQueryBuilder" parameters. If you can help me to progress. Thank's in advance
I don't find examples in stack with Easyadmin 4. And (I'm sorry), documentation is not very clear for me.
Example:
class UserCrudController extends AbstractCrudController
{
// ...
public function configureFields(string $pageName): iterable
{
return [
TextField::new('fullName'),
// ...
];
}
public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
$queryBuilder = parent::createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);
// if user defined sort is not set
if (0 === count($searchDto->getSort())) {
$queryBuilder
->addSelect('CONCAT(entity.first_name, \' \', entity.last_name) AS HIDDEN full_name')
->addOrderBy('full_name', 'DESC');
}
return $queryBuilder;
}
}
Why we have "entity.first_name" (why entity word and not entityDto...). dump parameters don't give me persuasive results
Easy finally.
You can choice the field you want to be rendered. Basically add __toString in Entity.
In my case just add for a many to many relation:
AssociationField::new('dances')
->setFormTypeOption('choice_label','level.style'),

TYPO3 - Retrieved TypoScript in itemsProcFunc are incomplete

I have following problem:
We are overriding the tt_content TCA with a custom column which has an itemsProcFunc in it's config. In the function we try to retrieve the TypoScript-Settings, so we can display the items dynamically. The problem is: In the function we don't receive all the TypoScript-Settings, which are included but only some.
'itemsProcFunc' => 'Vendor\Ext\Backend\Hooks\TcaHook->addFields',
class TcaHook
{
public function addFields($config){
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$configurationManager = $objectManager->get('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
$setup = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
);
}
$setup is now incomplete and doesn't contain the full TypoScript, for example some of the static-included TypoScript is missing.
Used TYPO3 7 LTS (7.6.18), PHP 7.0.* in composer-mode.
Does anybody know where the problem is? Is there some alternative?
You maybe misunderstood the purpose of TypoScipt. It is a way of configuration for the Frontend. The Hook you mentioned is used in the TCA, whích is a Backend part of TYPO3. TypoScript usually isn't used for backend related stuff at all, because it is bound to a specific page template record. Instead in the backend, there is the TSConfig, that can be bound to a page, but also can be added globally. Another thing you are doing wrong is the use of the ObjectManager and the ConfigurationManager, which are classes of extbase, which isn't initialized in the backend. I would recommend to not use extbase in TCA, because the TCA is cached and loaded for every page request. Instead use TSConfig or give your configuration settings directly to the TCA. Do not initialize extbase and do not use extbase classes in these hooks.
Depending on what you want to configure via TypoScript, you may want to do something like this:
'config' => [
'type' => 'select',
'renderType' => 'singleSelect',
'items' => [
['EXT:my_ext/Resources/Private/Language/locallang_db.xlf:myfield.I.0', '']
],
'itemsProcFunc' => \VENDOR\MyExt\UserFunctions\FormEngine\TypeSelectProcFunc::class . '->fillSelect',
'customSetting' => 'somesetting'
]
and then access it in your class:
class TypeSelectProcFunc{
public function fillSelect(&$params){
if( $params['customSetting'] === 'somesetting' ){
$params['items'][] = ['New item',1];
}
}
}
I had a similar problem (also with itemsProcFunc and retrieving TypoScript). In my case, the current page ID of the selected backend page was not known to the ConfigurationManager. Because of this it used the page id of the root page (e.g. 1) and some TypoScript templates were not loaded.
However, before we look at the solution, Euli made some good points in his answer:
Do not use extbase configuration manager in TCA functions
Use TSconfig instead of TypoScript for backend configuration
You may like to ask another question what you are trying to do specifically and why you need TypoScript in BE context.
For completeness sake, I tested this workaround, but I wouldn't recommend it because of the mentioned reasons and because I am not sure if this is best practice. (I only used it because I was patching an extension which was already using TypoScript in the TCA and I wanted to find out why it wasn't working. I will probably rework this part entirely.)
I am posting this in the hope that it may be helpful for similar problems.
public function populateItemsProcFunc(array &$config): array
{
// workaround to set current page id for BackendConfigurationManager
$_GET['id'] = $this->getPageId((int)($config['flexParentDatabaseRow']['pid'] ?? 0));
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$configurationManager = $objectManager->get(BackendConfigurationManager::class);
$setting = $configurationManager->getTypoScriptSetup();
$templates = $setting['plugin.']['tx_rssdisplay.']['settings.']['templates.'] ?? [];
// ... some code removed
}
protected function getPageId(int $pid): int
{
if ($pid > 0) {
return $pid;
}
$row = BackendUtility::getRecord('tt_content', abs($pid), 'uid,pid');
return $row['pid'];
}
The function getPageId() was derived from ext:news which also uses this in an itemsProcFunc but it then retrieves configuration from TSconfig. You may want to also look at that for an example: ext:news GeorgRinger\News\Hooks\ItemsProcFunc::user_templateLayout
If you look at the code in the TYPO3 core, it will try to get the current page id from
(int)GeneralUtility::_GP('id');
https://github.com/TYPO3/TYPO3.CMS/blob/90fa470e37d013769648a17a266eb3072dea4f56/typo3/sysext/extbase/Classes/Configuration/BackendConfigurationManager.php#L132
This will usually be set, but in an itemsProcFunc it may not (which was the case for me in TYPO3 10.4.14).

sails many to many associations failing to save

My sails many to many associations have stopped saving changes, that is, if I deselect one of the items in my checkbox list, or select a new one, the changes are not saved (populated to the join table).
It used to work, although I am not sure how long it's been broken for.
All the other fields on the page save correctly.
So I know the mechanics of most of it are correct, just the many to many associations, ie, updating the list of active records in the join table.
Any hints on what I can be doing wrong in my save?
I have the following models:
/**
* User.js
*/
module.exports = {
attributes: {
projects: {
collection: 'project',
via: 'users'
},
}
/**
* Project.js
*/
module.exports = {
attributes: {
users: {
collection: 'user',
via: 'projects',
dominant: true
},
}
In my form I am returning a checkbox list like such
{ projectname: 'AS Story Database',
userlist: [ '10', '3', '1' ], <-- this line is the many to many line from the check boxs
projecttype: 'Development',
companyid: '1',
startdate: 'Sat Jan 01 2011 00:00:00 GMT+1100 (AUS Eastern Daylight Time)',
enddate: '' }
}
I tried populating the result set
Project.findOne({'id':id})
.populate('users') <--------- heres the populate I added but didnt seem to have effect
.exec(function(err,project){
This is the save dialog in my sails controller
var a=req.param('project',null);
console.log(a); <-- note this is where the json above is output
project.projecttype= a.projecttype,
project.projectname= a.projectname,
project.companyid= a.companyid,
project.users= a.userlist, <-- this is the many to many association that used to work
project.startdate = a.startdate,
project.enddate = a.enddate
project.save(function(err,updated){ <-- here is the save function
if (err) {
req.session.flash = {'err':err};
sails.controllers.project.edit(req,res);
}else{
req.session.flash = {};
res.redirect('project/index');
}
});
#Sangharsh is correct in his comment above; you cannot update a collection by assigning an array to it and calling .save(). You may be thinking of .update(), which in Sails v0.12.x allows you to provide an array of objects to replace the existing set (although this has been removed in Sails 1.0 since it caused a lot of bugs and confusion).
The correct way to update an existing instance's collection in Sails v0.12.x is to use the .add() and .remove() methods. See the many-to-many associations doc page for more info.
In Sails 1.0, the .save() method of individual records has been removed to make things clearer; you always use the .addToCollection(), .removeFromCollection() and .replaceCollection() model class methods to manipulate plural associations.
Ok; I finally figured this out.
The method above (replaceCollection) only works on the older (0.x) versions of sails.
To get it working in the modern version, use
<model>.update('id':<the recordID>},{'<association name>':<list of new records>})
.exec(function(err,updated){
-do something-
});
ie -
Project.update({'id':id},{'users': a.userlist}).exec(function(err,updated){
project.save(function(err,updated){
//console.log(updated);
if (err) {
console.log(err);
req.session.flash = {'err':err};
sails.controllers.project.edit(req,res);
}else{
req.session.flash = {};
res.redirect('project/index');
};
});
});

Neo4j+PopotoJS: filter graph based-on predefined constraints

I have a question about the query based on the predefined constraints in PopotoJs. In this example, the graph can be filtered based on the constraints defined in the search boxes. The sample file in this example visualizations folder, constraint is only defined for "Person" node. It is specified in the sample html file like the following:
"Person": {
"returnAttributes": ["name", "born"],
"constraintAttribute": "name",
// Return a predefined constraint that can be edited in the page.
"getPredefinedConstraints": function (node) {
return personPredefinedConstraints;
},
....
In my graph I would like to apply that query function for more than one node. For example I have 2 nodes: Contact (has "name" attribute) and Delivery (has "address" attribute)
I succeeded it by defining two functions for each nodes. However, I also had to put two search box forms with different input id (like constraint1 and constraint2). And I had to make the queries in the associated search boxes.
Is there a way to make queries which are defined for multiple nodes in one search box? For example searching Contact-name and/or Delivery-adress in the same search box?
Thanks
First I’d like to specify that the predefined constraints feature is still experimental (but fully functional) and doesn’t have any documentation yet.
It is intended to be used in configuration to filter data displayed in nodes and in the example the use of search boxes is just to show dynamically how it works.
A common use of this feature would be to add the list of predefined constraint you want in the configuration for every node types.
Let's take an example:
With the following configuration example the graph will be filtered to show only Person nodes having "born" attribute and only Movie nodes with title in the provided list:
"Person": {
"getPredefinedConstraints": function (node) {
return ["has($identifier.born)"];
},
...
}
"Movie": {
"getPredefinedConstraints": function (node) {
return ["$identifier.title IN [\"The Matrix\", \"The Matrix Reloaded\", \"The Matrix Revolutions\"]"];
},
...
}
The $identifier variable is then replaced during query generation with the corresponding node identifier. In this case the generated query would look like this:
MATCH (person:`Person`) WHERE has(person.born) RETURN person
In your case if I understood your question correctly you are trying to use this feature to implement a search box to filter the data. I'm still working on that feature but it won't be available soon :(
This is a workaround but maybe it could work in your use case, you could keep the search box value in a variable:
var value = d3.select("#constraint")[0][0].value;
inputValue = value;
Then use it in the predefined constraint of all the nodes type you want.
In this example Person will be filtered based on the name attribute and Movie on title:
"Person": {
"getPredefinedConstraints": function (node) {
if (inputValue) {
return ["$identifier.name =~ '(?i).*" + inputValue + ".*'"];
} else {
return [];
}
},
...
}
"Movie": {
"getPredefinedConstraints": function (node) {
if (inputValue) {
return ["$identifier.title =~ '(?i).*" + inputValue + ".*'"];
} else {
return [];
}
},
...
}
Everything is in the HTML page of this example so you can view the full source directly on the page.
#Popoto, thanks for the descriptive reply. I tried your suggestion and it worked pretty much well. With the actual codes, when I make a query it was showing only the queried node and make the other node amount zero. I wanted to make a query which queries only the related node while the number of other nodes are still same.
I tried a temporary solution for my problem. What I did is:
Export the all the node data to JSON file, search my query constraint in the exported JSONs, if the file is existing in JSON, then run the query in the related node; and if not, do nothing.
With that way, of course I needed to define many functions with different variable names (as much as the node amount). Anyhow, it is not a propoer way, bu it worked for now.

Storing graph-like structure in Couch DB or do include_docs yourself

I am trying to store network layout in Couch DB, but my solution provides rather randomized graph.
I store a nodes with a document:
{_id ,
nodeName,
group}
and storing links in traditional:
{_id, source_id, target_id, value}
Following multiple tutorials on handling joins and multiple relationship in Couch DB I created view:
function(doc) {
if(doc.type == 'connection') {
if (doc.source_id)
emit("source", {'_id': doc.source_id});
if(doc.target_id)
emit("target", {'_id': doc.target_id});
}
}
which should have emitted sequence of source and target id, then I pass it to the list function with include_docs=true, assumes that source and target come in pairs stitches everything back in a structure like this:
{
"nodes":[
{"nodeName":"Name 1","group":"1"},
{"nodeName":"Name 2","group":"1"},
],
"links": [
{"source":7,"target":0,"value":1},
{"source":7,"target":5,"value":1}
]
}
Although my list produce a proper JSON, view map returns number of rows of source docs and then target docs.
So far I don't have any ideas how to make this thing working properly - I am happy to fetch additional values from document _id in the list, but so far I havn't find any good examples.
Alternative ways of achieving the same goal are welcome. _id values are standard for CouchDB so far.
Update: while writing a question I came up with different view which sorted my immediate problem, but I still would like to see other options.
updated map:
function(doc) {
if(doc.type == 'connection') {
if (doc.source_id)
emit([doc._id,0,"source"], {'_id': doc.source_id});
if(doc.target_id)
emit([doc._id,1,"target"], {'_id': doc.target_id});
}
}
Your updated map function makes more sense. However, you don't need 0 and 1 in your key since you have already "source"and "target".

Resources