🇫🇷France @gilbertdelyon

Account created on 28 October 2007, about 17 years ago
#

Recent comments

🇫🇷France gilbertdelyon

@tush001
Thank you for this advice.
Thanks to   This post   💬 Replace files through FTP Fixed  I wrote a small module that does the work easily and safely.

🇫🇷France gilbertdelyon

Thank you @katorymnd
I have  never used Drush before. I always update  with
composer update drupal/core-recommended --with-dependencies

Up to 10.2.2 it was updating the site as expected

But now, doing the same way doesn't uapdate to 10.2.4

Instead composer is returning message saying there is nothing to be installed or updated.

Same result with composer require drupal/core-recommended --with-all-dependencies

Why do you think running Drush will help solving this issue?

I have in mind something  is wrong in   composer.json , but I dont know what and where to look for

🇫🇷France gilbertdelyon

OK,
But I am now waiting for the next release and see if the same issue occurs again.
Because in a fresh D10.2.3 with no other module than AP (free of any rule) I couldn't update from beta 6 to beta7 with composer update drupal/access_policy while I had no issue in other modules with same procedure.
Wait and see!

🇫🇷France gilbertdelyon

Finally I removed all elements of access_policy module in folder and db, installed beta7 version, reconfigure the rules
It was a pain, but it woks!

🇫🇷France gilbertdelyon

Note that I've never seen composer used like composer update drupal.access_policy. When I ran composer update drupal/access_policy it updated successfully.

Oups, Sorry, keyboard error from my side. You are right, i also use composer update drupal/access_policy.

Another test:
Access_policy beta 6 is installed.
admin>extends>uninstall access_policy
composer remove drupal/access_policy
now the site is clear from any access_policy elements.

composer require drupal/access_policy:1.0.0-beta6
admin>extends>install access_policy
it works but I dont set any rule

composer update drupal/access_policy

Loading composer repositories with package information
Updating dependencies
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove

Very strange!

Then admin > extend > uninstall access_policy
composer remove drupal/access_policy

composer require drupal/access_policy:1.0.0-beta7
admin>extends>install access_policy
it works!

Notice that I have used composer this way to update contrib modules and this is the first time there is an issue.

🇫🇷France gilbertdelyon

@partigital
Sorry I dont use drush yet.

but as you can see in my previous comment
When I enter composer update drupal/access_policy
I get this answer in terminal:

Loading composer repositories with package information
Package "drupal.access_policy" listed for update is not locked.
Updating dependencies
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove

Strange that there is Nothing to modify in lock file and Nothing to install, update or remove

Then when I open foldersite/composer.json this what I see

 "require": {
        "composer/installers": "^2.0",
        "drupal/access_policy": "1.0.0-beta6",
🇫🇷France gilbertdelyon

@partdigital
In my test site:
I uninstalled all none core modules (except Access_policy beta6)
I updated to D10.2.3
Update.php
run cron
admin > config > delete cache
Then in terminal
composer update drupal.access_policy

[faoa3352@cantonais drupal.iaou.fr]$  composer update drupal.access_policy
Loading composer repositories with package information
Package "drupal.access_policy" listed for update is not locked.
Updating dependencies
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
Generating autoload files
Hardening vendor directory with .htaccess and web.config files.
42 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Scaffolding files for drupal/core:

back to admin > extensions
Access_policy beta6 is still there

Next step: I will reinstall a fresh D10.2.3 release and test again

@rishabjasrotia

My question is to @gilbertdelyon are you using this service access_policy.validator somewhere in your custom module?

No, I dont use any kind of access_policy service in my custom modules

🇫🇷France gilbertdelyon

Notice:
Previous post was for Production site 'D10.2.3)

In Test site (D10.2) Access_Policy is installed but not configured (no policy)

🇫🇷France gilbertdelyon

See attached document
(I have only one policy)
gfamily_access_policy_config_240229.txt

🇫🇷France gilbertdelyon

Notice: same process for other modules updating. No issue.

🇫🇷France gilbertdelyon

This is what I did:
In a Production site (D10.2.3)
- In admin >config > performance > clear the cache
console:
composer update drupal/access_policy
back to the site admin
Clear the cache again
Admin > extensions
Access_policy Beta6 is still there (with your last patch!)

In a test site on same server (D10.2.2 with only a few modules - nearly empty site))
Same process
composer update drupal/access_policy
After update I go back to site and get this error

The website encountered an unexpected error. Try again later.
Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException: Circular reference detected for service "access_policy.validator", path: "access_policy.validator -> exception.access_policy_html". in Drupal\Component\DependencyInjection\Container->get() (line 147 of core/lib/Drupal/Component/DependencyInjection/Container.php).
Drupal\Component\DependencyInjection\Container->get() (Line: 440)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters() (Line: 237)
Drupal\Component\DependencyInjection\Container->createService() (Line: 177)
Drupal\Component\DependencyInjection\Container->get() (Line: 105)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch() (Line: 239)
Symfony\Component\HttpKernel\HttpKernel->handleThrowable() (Line: 91)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 58)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 704)
Drupal\Core\DrupalKernel->handle() (Line: 19)

Back to console
Downgrade to beta6. It works

🇫🇷France gilbertdelyon

It's written in this page. (One week by default)

By the way. Do you know if the hook_user_logout is triggered when a session will reach is lifetime and is automatically deleted by drupal system, or only when user will logout from his browser?

🇫🇷France gilbertdelyon

I need data to persist as long as session persists because it's a cookie value record.
It seems that by default the tempstorestrorage.private will be deleted after a week while session may persist much longer (30 days?).
So, I have the idea that tempstorestorage will not suit my needs. 
What do you think?

🇫🇷France gilbertdelyon

Thank you Jaypan,

You suggest tempstore.private service. I have never used this service before. I will check what I could to with it.

Session storage has the great advantage that, if the user deletes the cookies in his browser, orphan data his automatically deleted in DB after a while by Drupal system.

I have no idea if data stored  by tempstore.private  service would also be automatically deleted ? 

🇫🇷France gilbertdelyon

The site is a very small community site (a few tens of registerd users - 100% private) mainly used to display images and videos of family events and vacations + some blog articles + comments.
I want the medias to be private.
I have tested "private" file system. It works, but heavy medias (example: some 2Go videos) are displayed with latency. You need to wait up to 3 or 4 minutes before you can play the video (while only 10 to 15 seconds when stored in public files). I read that it could be faster with Xsendfile Apache module, but it is not available in our shared server.
So, what to do?
I have developped a small module that add a dedicated cookie and alter the htaccess file of public folder

hook_user_login(){
//add a random value dedicated cookie

//add a "require" line in htaccess file that will check the cookie
// add a session variable that will record the cookie value

}

hook_user_logout(){
//remove the corresponfing "require" line in htaccess file
}

I know it's a kind of DIY and not at all a good practice. BUT IT WORKS very vell and suits my poorman needs.
I would be happy if someone could suggest a better idea.

And now there is an issue:
When a logged user deletes the cookies in his brower the orphan session will remain:
- in DB
- in my altered htaccess file

The orphan session will be removed after a while by drupal system in DB, but not the one in htaccess.
So, from time to time (once a day) a CRON job will compare and clean the htaccess file. AND this is why I need to read session variables in all DB sessions and, in htaccess, delete the "require" lines that are not in DB.

In the mean time I found a way (inspired by this page) , and it works! 

Please do not hesitate to suggest other ways. I am only a part time hobbyist developper.

Thanks in advance

🇫🇷France gilbertdelyon

So, now I have another question about sessions
i set a  varianle this way in the current session:

\Drupal::request()
->getSession()
->set("item", "value");

And I get the value this way:

\Drupal::request()
->getSession()
->get("item");

It works for the current session, but in a CRON job I would leke to get the "item value" of every session in database.
Is there a simple Drupal way for this or should I write a query to get the "session" column values from "Sessions" table.

🇫🇷France gilbertdelyon

Thank you Jaypan,
You are right, I made mistake.
In the meantime I learned how to use session variarables and it will suit my needs on a much better way.
 

🇫🇷France gilbertdelyon

There are 4 types of media in our site
- image - single image
- image_1 - multiple images for events galeries (ex: weddings, holidays, birthdays...)
- documents
- viseos files

I recently moved all the existing files from "public" to "private".
I couldn't change, nor for "documents", neither for "videos"
but I could for "images"

This is strange. Would it come from the fact I have 2 types of image media?

🇫🇷France gilbertdelyon

Thank you, I will try

BTW: As explained in #6 , since I had this issue I now redirect by way of a hook instead of a controller (and it works!).
If the suggestion in #7 works, I worry If I should go back to a controller.
Which wy is the most recommended: hook or controller?

🇫🇷France gilbertdelyon

Already discussed in this thread https://www.drupal.org/project/drupal/issues/3336188 📌 Consider making file field upload destination changeable even after data exists Active
According to this thread it seams this issue is a Drupal Core native issue
So, what can I do?

🇫🇷France gilbertdelyon

What do you mean by you "cannot"? What actually happens as compared to what you expect?

This is what I mean:
In admin > structure >Type of media > Video File > Manage fields > Video file field > Field Storage > Upload destination
There are 2 "radoi" buttons
- Private
- Public
It is set to Public

I would like to change to public, but I cannot. The 2 buttons are greyed.
- Is there some setting elsewhere to make them changeable again?
- Is it impossible to change this setting after some files have been uploaded?

🇫🇷France gilbertdelyon

I can confirm-
- There is no "taxonomy" access rule in my settings
- Only one "content" access rule

🇫🇷France gilbertdelyon

That's me again.
May be I was wrong in my privious post.
I dont intend to restrict access to "Groupes Utilisateurs" taxonomy terms, but may be I did it by mistake, or unsufficiant knowledge of Access Policy settings (there is a learning curve for me because translation in french is only partial I need to understand many things)

See attached file.
Field access.png

So, I just made a test after selecting "Libre" (free) instead of "Droits" (Rights).
It doesn't change the behaviour. Only the patch does a good job!
I tested it in production site and it also works.

🇫🇷France gilbertdelyon

Are you by chance restricting taxonomy terms with an Access Policy? In particular, Groupes Utilisateurs?

No, Acces Policy only uses "Groupes Utilisateurs" taxonomy terms for content acces control, but doesn't control acces to terms.

🇫🇷France gilbertdelyon

The patch seems to work in my test site. :-))
I will test in production site and keep you informed.

I appreciate your prompt and efficient assistance. Thank you so much.

🇫🇷France gilbertdelyon

You are on the right way!
This is what I did:
in access_policy.module (line 327

/**
 * Implements hook_entity_field_access().
 */
function access_policy_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
/*
if ($items && $items->getEntity() instanceof AccountInterface) {
    return \Drupal::service('class_resolver')
      ->getInstanceFromDefinition(EntityOperations::class)
      ->userFieldAccess($operation, $field_definition, $account, $items);
  }
*/
  return \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityOperations::class)
    ->entityFieldAccess($operation, $field_definition, $account, $items);
}

This is the result:
bartik & bartiksub ("empty")
No more error. :-)
But of course the field is now displayed in user form, and this is not good ( I could hide it in css, bad practice )

Attach:
Crop of user fields
Crop of user fields form

🇫🇷France gilbertdelyon

result of investigations:
While running Bartik: I cannot reproduce the error

While running a subtheme of Bartik: I can easily reproduce the ERROR "line 256"

My subtheme is as simple as possible with only 2 files:
bartiksub.info.yml

name: BartikSub
type: theme
base theme: bartik
description: 'Theme enfant pour site G-FAMILY.'
version: '1.0'
core_version_requirement:  ^9 || ^10

bartiksub.theme

<?php
// that's all

So, my conclusion is that the error is coming from the fact that I am using a subtheme.
What do you think?

🇫🇷France gilbertdelyon

My site is running a custom subtheme of Bartik.
This subtheme as now been running for 2 years without any issue.
I can reproduce the error very easily

I just made some tests with native Bartik and also with Olivero, and...
In these themes I cannot reproduce the error.

So, the error could come from
- the fact I am using a subtheme
- or from my custom code
I will investigate and keep you informed.

🇫🇷France gilbertdelyon

See attached file
Something strange:
Access is controled as expected in my main site with this config, but...
There is probably someting wrong in it because if I import it in a clone of the main site, and then delete cache and rebuilt rights, access control is not working at all.
Thanks in advance for your help

🇫🇷France gilbertdelyon

Xdebug? I am not at all familiar with this tool. Seems it needs a learning curve. Sorry I will not be able to help in this way.
But in the meantime I found a way to trap the error more precisely, at least on my production site.
I explain how to,
Initial status:
A user, named “testuser”, tries to refresh his password. It works!
Repeat again a couple of times. Still works. So far so good.

Disconnect “testuser”
Connect as “admin”
Go to “admin/config/performances” and clear the cache.
(Notice: cache lifetime is set to 15 minutes on my site, may be not the best value?)
Disconnect “admin”

Now “testuser” tries again to refresh his password,
and BINGO! Here is the error in line 256.

Disconnect “testuser”
Try again to refresh password. It works!

Hope it can help.

🇫🇷France gilbertdelyon

Thanks for this prompt answer.
This morning it works again, without any changing any thing in the settings. But I am not confident an I will test again periodically
I will do my best and help you and find the culprit event, but I am not a professional coder, only a part time hobbyist.

Another thing I noticed:
When Acces Policy module is running,
and when user opens the "edit profile" form
he doesn't see the “visibility_users_groups” field.
When the admin opens the "user profile" form he can see it.

This is good, because only the admin can set the user groups,
but I dont know if it's the normal behaviour.
And may be this is the reason of the issue?

🇫🇷France gilbertdelyon

30 minutes later, that's me again, and again it doesn't work (same error)
So, I rebuilt rights, and now it works.
For how long?

🇫🇷France gilbertdelyon

'mytestsite" is in a subdomain "mytestsite.mydomain.fr"
So,
- I removed the subdomain
- create a new one with same name. "mytestsite.mydomain.fr" targeting to  "mytestsite" folder
Names of subdomain and target  names are the same as before
But now it works! And I don't understande why !

🇫🇷France gilbertdelyon

Thank you 
but that's already done 

🇫🇷France gilbertdelyon

Unfortunately I couln't find the reason.
Our custom module is redirecting anonymous users to login page by way of a controller (based on this example: https://drupal.stackexchange.com/a/223109)
Redirection works perfectly but style is not loaded when "aggregate css" is selected.

So we have deleted the controller and now we use a simple hook (https://drupal.stackexchange.com/a/295593) may be not the best practice but now it works!

🇫🇷France gilbertdelyon

Thank you again for this prompt answer.
In the meantime I found how to set Acces Policy so that an editor can select any of the terms and see his content in any case.

This is what I did:
Add a rule: Authored by current user: (Grant access if the content element is authored by the current user.)
Select Validation operator : "Any"
So simple.
Now it works according to my needs.

This module is brillant!

🇫🇷France gilbertdelyon

I found a way. may be not a good practice but it works!

First attempt:
In mymodule/src/EventSubscriber/Mysbsciber.php

$loginurl = Url::fromRoute('user.login')->toString(); 
$event->setResponse(new RedirectResponse($loginurl, 301));

It works only when aggregate CSS is disabled

Second attempt:
In mymodule/src/EventSubscriber/Mysbsciber.php

$loginurl = Url::fromRoute('user.login')->toString(); 
header('Location: '.$loginurl)
exit;

It works only when aggregate CSS is disabled

Third attempt:
In mymodule/src/EventSubscriber/Mysbsciber.php

$loginurl = Url::fromRoute('user.login')->toString(); 
?>
<script type="text/javascript"> window.location.rel="noopener" target="_blank" href= "<?=$loginurl?>";>
</script>
 <?php

It works in any case (css aggregate active or inactive)

🇫🇷France gilbertdelyon

@gouthamraon
Same issue on my side.
The site is 100% private.
I have a custom module that redirects unauthenticated users to login page.

It works like a charm when Aggregate CSS is not active
It doesn't work when Aggregate CSS is active (css is not loaded because wrong mime type, same error as yours)

Did you find a way in the meantime?

🇫🇷France gilbertdelyon

That's me again.
issue is solved :-)
In structure / Media type / image / Form display / Media library form was not set correctly.
Only the image field was in the form.
So,  I added the other fields (annotation, shooting date,...) and it works!

🇫🇷France gilbertdelyon

Thank you, I appreciate
So, I will close this issue.

🇫🇷France gilbertdelyon

Thank you for this prompt answer and for the piece of code.

If you performed that action with a role that wasn't allowed to assign the "department" policy for example, it wouldn't change the policy, even if the department field had a value.

As installing Acces Policy needs admin permissions I also resaved content with admin permissions, so I think this is not a big issue.

BTW. It seems your code is dedicated to nodes. Would also work for existing medias? (only for my personal knowledge - I had no access control over medias before using Access Policy module)

🇫🇷France gilbertdelyon

That's me again!
Seems to work as follows:
- Go to admin / content / filter published content / select all
- Go to bottom of the page and save content/all selected elements
A warning should be added to documentation because when a rule is not working as expected newbies like me can susspect a wrong setting while re-saving content will solve the issue.

🇫🇷France gilbertdelyon

That's a good question. 
No so easy to precisely measure, but, according to what I can read here and there, Apache seams to be  much more efficient than PHP  in this kind of task.
See also a question about the same matter here (HumHub is a php script that sends files only in the same way as in Drupal private file system ) and the answer is that we should use X-Sendfile.  
I see in HumHub script that it uses a readfile_chunk() function , but  automatically switches to X-Sendfile when it is available. 
So, why using X-Sendfile if PHP was as efficient as Apache?

🇫🇷France gilbertdelyon

So, let's do a test !
I built a small test site (pure PHP, Drupal is not involved) that can send image and video files in 2 different ways.

  1. The way it works with public files
    direct file url in a html tag <img src ="mydomain.xyz/my/folder/myfile.jpg">  or <video src ="mydomain.xyz/my/folder/myfile.mp4"> 
  2. The way it works with private files
    read the file and send the bytes to the client by way of a php function readfile("myfile.jpg")
    Notice: As  readfile("myfile.jpg") can over pass the  buffer capacity I also use a readfile_chunk("myfile.jpg" ) function for large files. Chunk size is set to 1 Megabytes.

And the result is as follows (Measuring php processing time only. Network and client work times  are not measured). 

  1. Direct way: php processing time is only a few micro seconds in any case. Then Apache does the work.
  2. Read and Serve by php: php processing time will vary according to the file size:
    4     Megabytes image file   : arround 20milliseconds
    21   Megabytes image file   : arround 2 seconds 
    600 Megabite video file       : arround 37 seconds 

Not a big surprise. The second way will generate significant work load.
So, I guess that for large files publishing or for a large community site with many images,  using private files is not the right way, unless you can use a dedicated Apache module as X-Sendfile (unfortunately not available in our shared server)     

🇫🇷France gilbertdelyon

Yes this is what I begin to understanding because there is no "media_acces" table and I see that "node_acces" table is only for "pure" nodes, not for other kinds of entities.
So the node acces control mechanism seems to be available only for nodes!
 

🇫🇷France gilbertdelyon

You are right, I understand...
In fact I am on the way to decide between public files vs private files for my "small community fully private site"
This site will be populated with many media files (images, vidéos..)

I have in mind that private files is the way to go, but I read many "warnings" about performance.

As far as I can see in my test site there is not such a big difference between private and public loading time and as it is only a small community it should not generate significant server CPU load.

What do you think? 

🇫🇷France gilbertdelyon

Thank you, I will try

🇫🇷France gilbertdelyon

So, I understand that this could prevent attacks by malicious file uploading.
I guess it could be usefull for a large public site but may not so much for my small community fully private site .

🇫🇷France gilbertdelyon

#13 Queue emails to send in background Closed: duplicate
Sounds good. I am impatiently waiting for the next release!

🇫🇷France gilbertdelyon

I have added this this piece of code in a controller in D10.
May be there is simpler way, but It works!

private function updatevideoFilesize(){
        
        // ftech video files in file_managed table
        $db = \Drupal::service('database');
        $query = $db->select('file_managed', 't')->fields('t', ['fid','uri', 'filesize']);
        $query->condition('filemime', "video%", 'LIKE');
        $videofiles = $query->execute()->fetchAll();
        
        // variable to be filled with processing reports during the loop
        $output = ''; 
        
        // Loop through the files 
        foreach ($videofiles as $file) {
            
            //$output.= 'fid = '.$file->fid.' | uri = '.$file->uri.' | sizeBEFORE = '.$file->filesize.'<br/>'; //debug
         
            //Load the file entity by URI
            $loadedfile = \Drupal::entityTypeManager()
                            ->getStorage('file')
                            ->loadByProperties(['uri' => $file->uri]);
             
            // Check if the file entity was loaded successfully.
            //$output.= $loadedfile ? 'successfull load YES <br/>': 'successfull load NO<br/>';//debug
            
            // Get real file size
            $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager')->getViaUri($file->uri);
            $file_path = $stream_wrapper_manager->realpath();
            $realFileSize = filesize($file_path);
            
            if($realFileSize != $file->filesize){
            
                //$output.=  $file_path.' | realSIZE = '. $realFileSize.'<hr/>'; //debug
    
                // Store real size of file
                $query = $db->update('file_managed')->fields(['filesize'=>$realFileSize] );
                $query->condition ('fid',$file->fid,'=');
                $query->execute();
                
                $output .= 'fid = '.$file->fid.' | uri = '.$file->uri.'<br/>';
                $output .= 'former size = '.$file->filesize.' | new size = '.$realFileSize.'<hr/>';
                
            }//end if
            
        } //end foreach 
        
         
        $output = ($output =='')? 'No filesize to be updated' : 'Following filesizes have been uptdated.<hr/>'.$output;
        
        return $output;
        
   }//fin function
🇫🇷France gilbertdelyon

This thread is exactly what I need.
But of course it does not work in DRUPAL 10. (deprecated functions)
Would somebody be so kind to help me finding how to code this in D10?

Thanks in advance

🇫🇷France gilbertdelyon

@VM
Good idea ! Thank you
View saves my day!

🇫🇷France gilbertdelyon

@sunnypharma,
Please, what do you mean excatly?
I dont see any variable connected to session cookie in sites/default/setting.php file.
The only setting I see is cookie_domain: 'domain.com' in sites/default/services.yml

🇫🇷France gilbertdelyon

hello Jaypan,
Thank you for prompt answer.
Please find here under some more details about what I am trying to do:
- I an trying to disable caching only for one single field of the node
- This field is "link" type (inputs are url and title)
- The target of the link is located  outside Drupal site.
- Target site is a custom made private file storage. 
- Url input is someting like https://myfilestore.xyz/index.php?file=a-private-file.ext
- Link URL in the rendered page is made of "url input"+a-one-shot-crypted-key-that-will-allow-file-loading
- So, rendered url is someting like "https://myfilestore.xyz/index.php?file=a-private-file.ext&key=a-one-shot-crypted-key-that-will-allow-file-loading
- So, the key cannot be entered in the field input.
- It needs to be processed at each page relaod.
 

🇫🇷France gilbertdelyon

Sorry, I am only a poor old (very old!) part time hobyist self made developper and I did not have in mind that my poor skills could help confirmed coders!
In addition I have been very busy these monthes without any time for Drupal.
So, let me explain how it works in my very humble module:
Please notice that this custom module is taylor made for my needs, so you will see hereunder only some abstracts in regard with mailing:

1 - Queueing:
Drupal queing is very simple to use (you only have to google a bit!):
Somewhere in your code you will prepare the data that will be used for your mailng and then, thanks to the above function you will queue this data. Then it will be used at next CRON .

/**
  * Somewhere in you module
  * for example in a custom service
  *
  */
 
  /**
   * Queueing function
   * $notifdata is an array that will include all the resqted stuff for mail processing (subject, content, to, from,...)
   * Each item of the array is for ONE email
   *
   */  
  protected function queueing($notifdata){ 
  
        $queue = \Drupal::queue('my_queue_name');
        $queue->createQueue();             

	foreach ($notifdata as $item => $value){
		$queue->createItem($value); //One queue item per email
	}//end foreach
        
    }//end function

Cannot be more simple!

2 - Unqueueing:
Unqueing can be made in different ways:
- Old fashion by way of a hook_cron() function
- New fashion by way of a queueWorker.
As I am an old guy I will use the old fashion.

So, here is the hook_cron() function in my_module.module file

/**
 * Implements hook_cron()
 * This function will send email at each crom
 * 
 */

function mycustommodule_cron() {

     //My queue
      $myqueue = \Drupal::queue('my_queue_name');
      
      // Number of queue items to be sent at each cron 
      // (You have to set this value somewhere in you module config)
      $nbitems = mycustommodule_settings()["maxiItemsPerCron"];
      
      //Items processing
      for ($i=0; $i<($nbitems); $i++){
       
        // Test if items  to be processed from the queue
        // $queue->claimItem() returns only one item from the queue
        if ($queue_item =  $myqueue->claimItem()) {
                
            //Extract data from item
            $notifdata = $queue_item->data;
            
            //Send Email (using a custom service )
            $notif = \Drupal::service('my_custom_service');
            $sendnotif = $notif->sendnotif2users($notifdata); // sendnotif2users() method is now trigered
            //Delete item if success
            if($sendnotif){
                 $myqueue->deleteItem($queue_item);
            }//fin if

        }//fin if
      
    }//fin for
}//end function

3 - Sending the emails
In my custom module, heach time an item will be unqueued in hook_cron() the sendnotif2users() method (from my_custom_service) will be triggered.
You can also simply use a function. IMHO services is the best way.

/**
 * In my_custom_service file
 *
 */
namespace Drupal\node2notifs\NotifServices;

use Drupal\Core;

//Compléments pour envoi mails avec SymfonyMailer
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

/**
 * This function will mainly process the email content  and trigger the sending process (one email per target adress)
 *
 */ 
 
 public function sendnotif2users($notifdata) { 
                
	// Prossessing the email content
	$this->mailcontents($notifdata); // mailcontents() to be coded as as per your needs
                
        // Targets
	$targets = ["name1@domain1","name2@domain2","name3@domain3","name4@domain4", ];// array of all target email adresses
               
        //Sending loop
        foreach($targets as $item => $to){

              $this->to = $to;
              $this->sendEmail();//here we send an email only ONE email 
				   
        }//fin foreach
                
         return TRUE;  //This will allow queue item delete in  hook_cron()
               
 }//fin public  function

4 - And finally the mail is sent via SymfonyMailer
Of course you have to install Symfony Mailer and use the relative classes in your service (see heareabove)

 /**
 * This function will send the email with help of SymfonyMailer
 *
 */
 
 public function sendEmail() {

        $email = (new Email())
            ->from( \Drupal::config('system.site')->get('mail'))
            ->to($this->to)
            //->cc('cc@example.com')
            //->bcc('bcc@example.com')
            //->replyTo('replyto@example.com')
            //->priority(Email::PRIORITY_HIGH)
            ->subject($this->subject)
            ->text( $this->plaintextbodybuilder() )
            ->html( $this->htmlbodybuilder() );

        $transport = Transport::fromDsn('sendmail://default');
        $mailer = new Mailer($transport);
        $mailer->send($email);

    }//fin function

Please forgive some possible mistakes, I am only a poor hobbyist.
I hope this can help

🇫🇷France gilbertdelyon

In the meantime I found a codeless way with combination of 2 much more popular modules:
File (field) path & Token  (random token)

🇫🇷France gilbertdelyon

In the meantime I found a "very bad practice, but efficient" way. 
Step 0: Set a video type media with a specfic folder for the files
Step 1: Create media with  a small video file.
Step 2: via FTP, open the video files folder and replace the small file by the very large file, without changing the file name.

It works, but small file size remains in database.  Thanks to  This post   💬 Replace files through FTP Fixed the file size should be easy to update.
 

🇫🇷France gilbertdelyon

This Edit Media Library  module solve the issue, 
but it works only when media is embeded in a field. (this should be a core functionnality)
it doesn't work when media is embeded in a text editor.

Better than nothing!

🇫🇷France gilbertdelyon

Yes, this is what I found in the meantime.
But I also found a new "side issue": if the small icon isn't inside one of the images you cannot click it, because it will disappear when the pointer will go outside of the image.

🇫🇷France gilbertdelyon

What is the reason to set "unlimited" items for the image field?

Because I already have a custom field formatter that can display a "multiple image field" as a gallery with a javascript overlay (a kind of custom  "colorbox" ).

By the way, I am looking for a way to adapted this field formatter to a "multiple single image media  field" up up to now I didn't succeed.

🇫🇷France gilbertdelyon

You cannot edit the field from content edit page, but you can from the diplayed content (small icon on the upper right corner)

🇫🇷France gilbertdelyon

You are right. Thank you to point this out 

I had in mind that html of a field based on media entity  was very different and more complex than a "basic" image field, but in fact it is the same structure.

So, I can easily adapt my custom formatter and it should work

Thanks again

🇫🇷France gilbertdelyon

+1
Impatiently waiting for this module to work with CKE 5

Production build 0.71.5 2024