? ? Pending

User tests: Successful: Unsuccessful:

avatar laoneo
laoneo
27 Aug 2021

Summary of Changes

In media manager we have events for the CUD operations but not for the read one. This pr adds the missing events.

During all events the objects can be manipulated, except the getUrl one. There it is possible for subscribers to provide a new url.

@wilsonge code review as there is nothing to test when all system tests are passing.

Testing Instructions

Open the media manager in the back end.

Actual result BEFORE applying this Pull Request

All is working as expected.

Expected result AFTER applying this Pull Request

All is working as expected.

avatar laoneo laoneo - open - 27 Aug 2021
avatar laoneo laoneo - change - 27 Aug 2021
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 27 Aug 2021
Category Administration com_media
avatar dgrammatiko dgrammatiko - test_item - 27 Aug 2021 - Tested successfully
avatar dgrammatiko
dgrammatiko - comment - 27 Aug 2021

I have tested this item successfully on e5dc8dd


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar laoneo laoneo - change - 4 Sep 2021
Labels Added: ?
avatar alikon alikon - test_item - 4 Sep 2021 - Tested successfully
avatar alikon
alikon - comment - 4 Sep 2021

I have tested this item successfully on 40c3b81


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar dgrammatiko dgrammatiko - test_item - 4 Sep 2021 - Tested successfully
avatar dgrammatiko
dgrammatiko - comment - 4 Sep 2021

I have tested this item successfully on 40c3b81


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar Fedik
Fedik - comment - 4 Sep 2021

@laoneo I have thought about that thing with result for $newUrl, and I think correct would be to get result from the event instead of dispatcher. I suggest you next:

The event class, that have defined URL get/set:

namespace Joomla\Component\Media\Administrator\Event;

class MediaFileUrlEvent extends AbstractEvent
{
    public function __construct($name, array $arguments = array())
    {
        parent::__construct($name, $arguments);

        // Check for required arguments
        if (empty($arguments['url']) || !is_string($arguments['url']))
        {
            throw new BadMethodCallException("Argument 'url' of event $name is empty or not of the expected type");
        }
    }
    public function getUrl(): string
    {
        return parent::getArgument('url');
    }

    public function setUrl(string $url)
    {
        parent::setArgument('url');
    }
}

Triggering the Event:

$url   = $this->getAdapter($adapter)->getUrl($path);
$event = new MediaFileUrlEvent('onFetchMediaFileUrl', ['url' => $url]);

Factory::getApplication()->getDispatcher()->dispatch(
  $event->getName(),
  $event
);

$newUrl = $event->getUrl();

Plugin listener:

public function onFetchMediaFileUrl(MediaFileUrlEvent $event)
{
    $event->setUrl('blabla/my/url.jpg');
}

As you see it more straightforward ;)

@nibra @HLeithner please confirm, or maybe I wrong

avatar nibra
nibra - comment - 4 Sep 2021

Regarding 'get result from the event instead of dispatcher':
This is more a matter of taste. One big source of confusion is that in Joomla, calling a plugin is always called triggering an event, although plugins can be event handlers but also just hooks.

Events are usually just emitted without expecting (or waiting for) results. Other parts of the software or even other systems may or may not react on those events.

Hooks are a technique to inject code - they get some input data and have a return value. Thus they can alter values or provide new data.

In Joomla, we have no distinction between those two approaches. We just have plugins that might or might not return values. In Joomla, we're using events to communicate with the plugins. If a plugin returns a value, it is expected that the value is returned by the dispatch() method.

In the present case, both @laneo's and @Fedik's approaches are valid an can be considered 'clean', while @laoneo's is more 'Joomla like'.

avatar Fedik
Fedik - comment - 4 Sep 2021

@nibra thanks for clarification

avatar laoneo
laoneo - comment - 6 Sep 2021

So boys, I hope now everybody is happy and we can get it merged.

avatar Fedik
Fedik - comment - 6 Sep 2021

@laoneo I made PR to your branch,
then it should be good

avatar laoneo
laoneo - comment - 6 Sep 2021

Merged

avatar laoneo
laoneo - comment - 7 Sep 2021

Event calls are now the same across all methods. Can be tested now again.

avatar HLeithner
HLeithner - comment - 23 Sep 2021

The event set functions need validators, Like is_array at least for setFiles and is_string for setUrls like in the constructor. Also the parameters must be Immutable (which is already done in the events).

avatar laoneo
laoneo - comment - 23 Sep 2021

There are no set functions in the new events.

avatar HLeithner
HLeithner - comment - 23 Sep 2021

There are no set functions in the new events.

in this case it makes no sense to use return $event->getFiles(); when it's not planned that t he values can be changed by a plugin.

avatar HLeithner
HLeithner - comment - 23 Sep 2021

Re reading your opening post you say

During all events the objects can be manipulated, except the getUrl one. There it is possible for subscribers to provide a new url.

doesn't that mean the plugins should/can change the event attributes?

avatar laoneo
laoneo - comment - 23 Sep 2021

You can change by setArgument() which is a public function in the event. It is intended to give the plugin full control over the returned data. Better would be to make a proposal, instead of getting into an argument. All I want is to have these events in MM without over engineering the whole thing.

avatar Fedik
Fedik - comment - 23 Sep 2021

@laoneo I think @HLeithner means something like there:

/**
* Setter for the subject argument
*
* @param JTableInterface $value The value to set
*
* @return JTableInterface
*
* @throws BadMethodCallException if the argument is not of the expected type
*/
protected function setSubject($value)
{
if (!\is_object($value) || !($value instanceof JTableInterface))
{
throw new BadMethodCallException("Argument 'subject' of event {$this->name} is not of the expected type");
}
return $value;
}

It does not have setter for subject, however the Event class will call protected setSubject, to validate the subject if someone will do $event->setArgument('subject', $foobar);

So we have validation in both cases, in __constructor and setArgument

avatar HLeithner
HLeithner - comment - 23 Sep 2021

You can change by setArgument() which is a public function in the event. It is intended to give the plugin full control over the returned data. Better would be to make a proposal, instead of getting into an argument. All I want is to have these events in MM without over engineering the whole thing.

It's not about over engineering it's that the new event system should be clean and safe, that's the reason for validation.

Fedir already wrote it.

Adding

    public function setUrl(string $url)
    {
        if (empty(url))
        {
            throw new BadMethodCallException("Argument 'url' is empty");
        }
        parent::setArgument('url');
    }

would fit the needs (at least for the one plugin).

avatar Fedik
Fedik - comment - 23 Sep 2021

@HLeithner there a caveat,

public function setUrl(string $url)
{
  if (empty(url))
  {
    throw new BadMethodCallException("Argument 'url' is empty");
  }
  parent::setArgument('url');
}

This will lead to infinity loop ;)
The method should be protected.

avatar HLeithner
HLeithner - comment - 23 Sep 2021

@HLeithner there a caveat,

public function setUrl(string $url)
{
  if (empty(url))
  {
    throw new BadMethodCallException("Argument 'url' is empty");
  }
  parent::setArgument('url');
}

This will lead to infinity loop ;)
The method should be protected.

haha I copied you example and you are right should be more like

protected function setUrl(string $url)
{
  if (empty(url))
  {
    throw new BadMethodCallException("Argument 'url' is empty");
  }
  return $url;
}
avatar Fedik
Fedik - comment - 23 Sep 2021

yeah, originally I also thought it should work,
but after couple tests I ended up with infinity loop :)

avatar laoneo
laoneo - comment - 23 Sep 2021

So instead of using the events arguments feature you want to store the url in an extra variable in the event class? I mean if a plugin wants to set an empty url then this is fine. If a plugin wants to set empty files this is also fine.

avatar HLeithner
HLeithner - comment - 23 Sep 2021

So instead of using the events arguments feature you want to store the url in an extra variable in the event class? I mean if a plugin wants to set an empty url then this is fine. If a plugin wants to set empty files this is also fine.

It's not an instead, that's how the event system works.

If it's ok that the file(s) is empty then we only have to validate that it is a string or an array (depending of the event).

The event constructor uses the the setArgument() function to save the variables in the $this->arguments array of the the event class.

the setArgument function checks if a set() function exists and uses it for validation. if it fails the event can't be created. That's the reason to do extra checks like !empty() in the constructor. In the setUrl() function we would then only validate that the provided parameter is an string.

avatar laoneo
laoneo - comment - 24 Sep 2021

Also make a pr against my branch with your suggestion.

ccd02cb 29 Sep 2021 avatar laoneo void
avatar laoneo
laoneo - comment - 29 Sep 2021

So changed it to an internal variable, hope @HLeithner is happy now and we can go ahead.

avatar HLeithner
HLeithner - comment - 29 Sep 2021

So changed it to an internal variable, hope @HLeithner is happy now and we can go ahead.

it has nothing to do to make me happy, it's about having a "bullet proof" api, which is the reason for the new event system. I will create pull request against your branch or commit directly what ever you prefer.

avatar laoneo
laoneo - comment - 29 Sep 2021

pr please

avatar HLeithner
HLeithner - comment - 29 Sep 2021

created a pull request Digital-Peak#17 would be good if @Fedik can have a look too.

avatar laoneo
laoneo - comment - 6 Oct 2021

Merged it. @wilsonge all ok here now

avatar laoneo
laoneo - comment - 24 Oct 2021

@HLeithner can you have a look on the system tests as they are failing since your changes got merged. Thanks.

avatar HLeithner
HLeithner - comment - 6 Nov 2021

I can replicate the problem locally but don't understand the reason.
It seems that the DELETE XHR request is not send to the server and the vue application is waiting for feedback that will never come because no request has been created. So I think it's unrelated to the PR but happens reliable in drone for this pr...

I can replicate this problem with Joomla 4.0.1, create a folder, click around (optioal), delete it. Sometimes the loading bar doesn't stop and no XHR DELETE request is send. Not sure for the reason. So may be completely unrelated to the current error.

avatar laoneo
laoneo - comment - 6 Nov 2021

Are you able to fix it?

avatar HLeithner
HLeithner - comment - 7 Nov 2021

Are you able to fix it?

wasted after of the day yesterday to debug drone but only found out that it fails as soon as line
$event = new FetchMediaFileEvent('onFetchMediaFile', ['file' => $file]);
is executed.

I debug this on my github account to reduce notifications to others HLeithner#38

last try was successful and I think (while writing this) that the problem is an empty directory.

avatar HLeithner
HLeithner - comment - 8 Nov 2021

@laoneo I think I would the reason the file API also sense directories against the File event

  [0]=>
  object(stdClass)#885 (13) {
    ["type"]=>
    string(3) "dir"
    ["name"]=>
    string(11) "test-folder"
    ["path"]=>
    string(34) "local-images:/test-dir/test-folder"
    ["extension"]=>
    string(0) ""
    ["size"]=>
    string(0) ""
    ["mime_type"]=>
    string(9) "directory"
    ["width"]=>
    int(0)
    ["height"]=>
    int(0)
    ["create_date"]=>
    string(25) "2021-11-08T20:09:15+00:00"
    ["create_date_formatted"]=>
    string(16) "2021-11-08 20:09"
    ["modified_date"]=>
    string(25) "2021-11-08T20:09:15+00:00"
    ["modified_date_formatted"]=>
    string(16) "2021-11-08 20:09"
    ["adapter"]=>
    string(12) "local-images"
  }

Which fails the file validation, so the question is now how to fix this. Add an additional event type or make the File event more generic. I would expect that a plugin would handle files and directories different.

avatar laoneo
laoneo - comment - 9 Nov 2021

There is no reason to handle directories different than files. Sending two events makes no sense as the result will be combined again and you loose the sorting when you combine them afterwards. All a developer wants is to have the possibility to interact with the result set before sending it to the client. I would suggest that your validation changes will be reverted and then when this one gets merged you can open a new pr with the validation stuff, so we can move forward with this pr. Otherwise it will never arrive in core and I need it for several reasons.

avatar bembelimen
bembelimen - comment - 9 Nov 2021

I think there is no need to rush this, as we have plenty of time to get it merged till the next release. There are several people supporting this function, so it's very likely that it's getting merged. BUt we should really go for best practise here.

I see two things which has to be done:

  • Rename the events (sorry for that) to communicate that there are possible files AND folders (e.g. FetchMediaItemEvent, FetchMediaListEvent, ...? anyone?)
  • Add the validation. As @HLeithner did the first validation, probably he will provide the last bits, too?

If both are ready and tested, I'm happy to merge.

avatar laoneo
laoneo - comment - 10 Nov 2021
* Rename the events (sorry for that) to communicate that there are possible files AND folders (e.g. FetchMediaItemEvent, FetchMediaListEvent, ...? anyone?)

The function names are getFile/getFiles, in Media Manager we always talk about files and not items. Adding now a different therm would confuse the developers.

avatar Fedik
Fedik - comment - 10 Nov 2021

I agree with @laoneo it does not make sense for 2 events.
Model::getFile[s]() handle both folder and files.

hm, only validation for type is

// Only "dir" or "file" is allowed
if (!isset($value->type) || ($value->type !== 'dir' && $value->type !== 'file'))
{
throw new BadMethodCallException("Property 'type' of argument 'file' of event {$this->name} has a wrong value. Valid: 'dir' or 'file'");
}

okay, I see, it need to exclude extension validation if type is DIR (or just remove this section).
Next will fail for folders always:

// A string
if (!isset($value->extension) || !is_string($value->extension))
{
throw new BadMethodCallException("Property 'extension' of argument 'file' of event {$this->name} has a wrong value. Valid: string");
}

avatar HLeithner
HLeithner - comment - 10 Nov 2021

A File is not a Folder, so a plugin developer would expect only a file, I don't know who named the function getFile but it seems it's simple wrong. Continuing the wrong wording make it worse.

Since we have now the time to do it right and don't need to rush out anything we should not introduce new "wrong" names.

Allon and fedir is right, having separate events is not needed since the type is in the object. Solving the validtion should be trivial (I will do this). I would also rename (in a b/c way, even if we have no b/c promise on this) the getFile(s) function to getItem(s) to reflect the real behavior.

avatar laoneo
laoneo - comment - 10 Nov 2021

But a folder is a file.

avatar HLeithner
HLeithner - comment - 10 Nov 2021

But a folder is a file.

yes in posix land because everything is a file... but we have separate functions to createFile and createFolder seems not to be the same.

avatar laoneo
laoneo - comment - 10 Nov 2021

Calm down, I will rename the events. All I want are the events, if the developers will understand then better, I'm fine with this.

avatar laoneo
laoneo - comment - 10 Nov 2021

System test still fails

avatar HLeithner
HLeithner - comment - 10 Nov 2021

System test still fails

Has also to be fixed in the Files variant of the Event.

avatar laoneo
laoneo - comment - 10 Nov 2021

Can you do that please.

avatar laoneo
laoneo - comment - 10 Nov 2021

Still not

avatar laoneo
laoneo - comment - 10 Nov 2021

You can push directly to the branch if you want. No need to make a suggestion first.

avatar Fedik
Fedik - comment - 10 Nov 2021

It also need to skip: size, width, height and other non folder thing.
btw, width, height valid only for images, and invalid for pdf and other documents and audio files

avatar HLeithner
HLeithner - comment - 10 Nov 2021

It also need to skip: size, width, height and other non folder thing. btw, width, height valid only for images, and invalid for pdf and other documents and audio files

if I'm not wrong I only check if it's an integer not if is > 0. What I have check in the original class it sets the values to 0.

avatar Fedik
Fedik - comment - 10 Nov 2021
if (!isset($value->width) || !is_integer($value->width))

isset() will return false if $value->width === null or not exists,
and I guess for a folder it can be one or another

avatar laoneo
laoneo - comment - 16 Nov 2021

Events have been renamed. @HLeithner can you please fix your part please.

avatar laoneo
laoneo - comment - 23 Nov 2021

@HLeithner can you please have a look on the errors?

avatar laoneo laoneo - change - 1 Dec 2021
The description was changed
avatar laoneo laoneo - edited - 1 Dec 2021
avatar Fedik
Fedik - comment - 5 Dec 2021

I have tested this item successfully on c42a582


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar Fedik Fedik - test_item - 5 Dec 2021 - Tested successfully
avatar Fedik
Fedik - comment - 5 Dec 2021

All seems works now, @HLeithner please confirm when you will have a min.

avatar HLeithner
HLeithner - comment - 5 Dec 2021

thanks @laoneo for fixing it your self and simplify the validation. thanks @Fedik for testing.
It looks ok for me. Maintainers have to decide in which branch it should be merged @bembelimen

avatar BPBlueprint BPBlueprint - test_item - 9 Dec 2021 - Tested successfully
avatar BPBlueprint
BPBlueprint - comment - 9 Dec 2021

I have tested this item successfully on c42a582


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar alikon alikon - change - 11 Dec 2021
Status Pending Ready to Commit
avatar alikon
alikon - comment - 11 Dec 2021

RTC


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35396.

avatar bembelimen
bembelimen - comment - 11 Dec 2021

I'm pretty sure, this should go into 4.1.

avatar laoneo laoneo - change - 11 Dec 2021
Labels Added: ?
avatar laoneo
laoneo - comment - 11 Dec 2021

Initially the changes have been small so it made sense at that time to go into 4.0. Now it makes more sense for 4.1. Rebased.

avatar laoneo laoneo - change - 11 Dec 2021
Title
[4.0] Add some events when fetching media data
[4.1] Add some events when fetching media data
avatar laoneo laoneo - edited - 11 Dec 2021
avatar bembelimen
bembelimen - comment - 16 Dec 2021

If you allow maintainer to change your code, I could trigger the sync with the base branch and merge. So for you you have to do it @laoneo , could you please do it?

avatar laoneo laoneo - change - 16 Dec 2021
Labels Added: ?
Removed: ?
avatar laoneo
laoneo - comment - 16 Dec 2021
avatar bembelimen
bembelimen - comment - 16 Dec 2021

Ah ok, thx.
Would you mind updating it so I can merge?

avatar laoneo
laoneo - comment - 16 Dec 2021

Did already

avatar bembelimen bembelimen - close - 16 Dec 2021
avatar bembelimen bembelimen - merge - 16 Dec 2021
avatar bembelimen bembelimen - change - 16 Dec 2021
Status Ready to Commit Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2021-12-16 22:44:12
Closed_By bembelimen
avatar bembelimen
bembelimen - comment - 16 Dec 2021

Thx

Add a Comment

Login with GitHub to post a comment