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

Multiple author affiliations #10460

Open
wants to merge 123 commits into
base: main
Choose a base branch
from

Conversation

GaziYucel
Copy link
Contributor

@GaziYucel GaziYucel commented Sep 20, 2024

GaziYucel and others added 30 commits September 20, 2024 14:33
/**
* Set name
*/
public function setName(?array $name): void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should stay consistent with other 'settings' method that could have locale and have something like:

    public function setName(string|array $name, ?string $locale = null)
    {
        $this->setData('name', $name, $locale);
    }

    public function getName(?string $locale = null)
    {
        return $this->getData('name', $locale);
    }

When you then provide an array as $name and no locale to setName() it will/should be set correctly.

}
yield $row->author_affiliation_id => $fromRow;
}
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not easy to read and understand, so maybe to do it similarly to author DAO and set affiliations?
To get the affiliation fromRow() and then get the Ror by ID and set the affiliations names.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we would also not need that function getManyRorAsCollectionId() in Ror Collector

public function fromRow(object $row): Affiliation
{
return parent::fromRow($row);
}
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function would then get the ror names and set the affiliation names to be the same as ror names


class Ror extends DataObject
{
public const int STATUS_ACTIVE = 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be public const STATUS_ACTIVE = 1; i.e. without the type int
here and below

{
$this->authorIds = $authorIds;
return $this;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this function is never used?
Then maybe to leave the filtering only by one author ID?

public ?string $name = null;

/** Get affiliations with a searchPhrase */
public ?string $searchPhrase = null;
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we do not consider this anywhere, so maybe to remove it for now.

function (JoinClause $join) {
$join
->on('r_s.setting_value', '=', 'a_s.setting_value')
->on('r_s.locale', '=', 'a_s.locale')
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does locale needs to be the same? 🤔

];
$affiliation->setAllData($params);

Repo::affiliation()->dao->updateOrInsert($affiliation);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In upgrade scripts we are using only SQLs and no objects and functions -- so that the upgrade can be correctly done for the given version even if we change the objects and code.
Thus, we should try to use the query builder to insert or update the affiliations.

];
$affiliation->setAllData($params);

Repo::affiliation()->dao->updateOrInsert($affiliation);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well, we should use the query builder to insert or update the affiliation

}
}

$affiliation->setAllData($params);
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to use setName, setRor and get rid of $params array.
(Then take care about the name, not to be overwritten.)

*/
public function getByAuthorId(int $authorId, ?string $submissionLocale = null): array
{
return iterator_to_array(
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of using the php function iterator_to_array we should use Laravel all() function:

$this->getCollector()
  ->filterByAuthorId($authorId)
  ->getMany($submissionLocale)
  ->all()

Here and elsewhere if similar cases exist...


$params['id'] = $newId;
$author->setId($newId);
$author->setAffiliations($params['affiliations']);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is $params['affiliations'] array of Affiliation objects?

Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should here do:

  1. Repo::affiliation()->validate($author, $params, $submission, $submissionContext);
  2. if error -> return
  3. Repo::affiliation()->newDataObject($params);
  4. author->setAffiliations...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also to do here:
foreach ($params['affiliations'] as $affiliationParam) {
then the steps above
and having Repo::affiliation()->validate(null, $params, $author, $submission, $submissionContext); i.e. validating only one affiliation i.e. having the first parameter Affiliation object -- see below where the validate is implemented.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also below, in the editContributor function

Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to create Affiliation objects and use author->setAffiliations (steps 1 - 4 above) before adding the author.
Then in the author DAO the author is first added and then the affiliations saved, containing the author ID.

@@ -1558,6 +1559,15 @@ public function addContributor(Request $illuminateRequest): JsonResponse

$author = Repo::author()->newDataObject($params);
$newId = Repo::author()->add($author);

$params['id'] = $newId;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be 'authorId' instead of 'id'?

$validator = ValidatorFactory::make(
$props,
$schemaService->getValidationRules(PKPSchemaService::SCHEMA_AUTHOR, $allowedLocales)
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think you need this

$allowedLocales = $submission->getPublicationLanguages($context->getSupportedSubmissionMetadataLocales());

// Check if author exists
if(!empty($props['id'])){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we call it authorId instead of id?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe to use isset($props['id'])

$schemaService->getValidationRules(PKPSchemaService::SCHEMA_AUTHOR, $allowedLocales)
);
$validator->after(function ($validator) use ($props) {
if (isset($props['id']) && !$validator->errors()->get('id')) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you check above for isset($props['id']) then no need here

*
* @hook Affiliation::validate [[&$errors, $object, $props, $submission, $context]]
*/
public function validate(?Author $author, array $props, Submission $submission, Context $context): array
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to have the syntax as in all validate functions: to validate only one affiliation and to have the first parameter Affiliation object that could be null ?

*/
public function saveAffiliations(Author $author): void
{
$affiliations = $author->getAffiliations();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we can expect the affiliations to always be an array of Affiliation objects. (I commented above in PKPSubmissionController in add/editContributor)

}

/**
* Get the localized affiliations as an array.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localized affiliations names


foreach ($this->getAffiliations() as $affiliation) {
foreach ($this->getLocalePrecedence($preferredLocale) as $locale) {
$name = $affiliation->getData('name');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the $locale parameter is missing here

foreach ($this->getLocalePrecedence($preferredLocale) as $locale) {
$name = $affiliation->getData('name');
if (!empty($name[$locale])) {
$value[] = $name[$locale];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be a break, in order not to collect names in all the locales

<complexType>
<sequence>
<element name="ror" type="string" minOccurs="0" maxOccurs="unbounded" />
<element name="name" type="pkp:localizedNode" minOccurs="0" maxOccurs="unbounded" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the minOccurs for ror and name be 1 -- if there is a rorAffiliation, then both elements should exist, no?

}
}
foreach($affiliations as $affiliation) {
if(!empty($affiliation->getData('ror'))) {
Copy link
Collaborator

@bozana bozana Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to have two times the same foreach($affiliations as $affiliation).
Maybe then to first check if(!empty($affiliation->getData('ror'))) { then add rorAffilaition element, else if (!empty($affiliation->getData('name') add affiliation element.

$locale = $publication->getData('locale');
}
$author->setAffiliation($n->textContent, $locale);
break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should stay, and the new element rorAffiliation needs to be considered as well, no?
Maybe the only thing is: if we have the affiliation element, if we would like to see if the ROR exists for it, like in the upgrade script 🤔

/**
* Get localized affiliations.
*/
public function getLocalizedAffiliations(?string $preferredLocale = null): array
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function does not seem to be quite right:
$affiliation->getLocalizedName() will not consider locale from the locale precedence,
and when a name value is found, we need to make a break (and not collect everything).

}

/**
* Get the localized affiliations as a string.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localized affiliations names

Copy link
Collaborator

@bozana bozana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @GaziYucel, thanks a lot for the good work and improvements!
I left a few comments.
I believe, that having the ROR object in an affiliation would make it easier to deal with names in different locales, e.g. we will not need to worry about setting ROR default name to the affiliation name with the submission locale, and also getting getLocalizedAffiliations... should be easier. I am only not sure how that would work with the ui-library... Let me know what do you think...

@@ -182,7 +182,7 @@ public function initData()
$data = [
'givenName' => $author->getGivenName(null), // Localized
'familyName' => $author->getFamilyName(null), // Localized
'affiliation' => $author->getAffiliation(null), // Localized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... This file is used in the quickSubmit plugin. I do not think we can use the new affiliationField UI component there :-( I/we need to think how to solve it best...

@@ -225,7 +225,7 @@ public function execute(...$functionParams)
$author->setGivenName(array_map('trim', $this->getData('givenName')), null);
$author->setFamilyName($this->getData('familyName'), null);
$author->setPreferredPublicName($this->getData('preferredPublicName'), null);
$author->setAffiliation($this->getData('affiliation'), null); // localized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for myself: For this file as well. It is only used in quickSubmit plugin and we need to see how to solve the new affiliations there for 3.5

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

Successfully merging this pull request may close these issues.

4 participants