3

Background

I'm writing a plugin that will function as a document-archive with access-rights to different folders set based on user-groups.

In addition to folders which are restricted, there is also one folder in the asset-source which is "open" to everyone.

I have the full plugin working; or at least so I thought until one of the test-users moved the "open" folder inside the asset-source trough the CP.

Suddenly the "open" folder (and it's contents) were no longer displayed anywhere.

I was fetching this folder based on it its ID.

Why you should not rely on folder-ids in Craft

Basically - folder-IDs are dynamic, which means that you cannot safely look up a folder by ID!

Let's do a little experiment.

Create an asset-source named My assets, and under it create two folders: Test and Test2

Now - if you look at your craft_assetfolders database-table, you'll see something akin to:

ID - parentId - sourceId - name        - path
77 - NULL     - 4        - "My-assets" - 
78 - 77       - 4        - "Test"      - "Test/"
79 - 77       - 4        - "Test2"     - "Test2/"

Note that id, parentId and sourceId might be different numbers in your example - they depend on how much your craft_assetfolders database-table contained before you started this example.

So far this all makes perfect sense - until you move a folder! Per example, drag and drop Test into Test2, then reload the view of your database-table

It will now read

ID - parentId - sourceId - name        - path
77 - NULL     - 4        - "My-assets" - 
79 - 77       - 4        - "Test2"     - "Test2/"
80 - 79       - 4        - "Test"      - "Test2/Test/"

What happened to id 78? It's gone! However the folder Test still exists, it still contains all of its assets etc - it just has a new ID.

Now - for the sake of experimenting, let us drag and drop Test back to the root of our asset-source and reload our view of the database-table

ID - parentId - sourceId - name        - path
77 - NULL     - 4        - "My-assets" - 
79 - 77       - 4        - "Test2"     - "Test2/"
81 - 77       - 4        - "Test"      - "Test/"

Basically - whenever you move an asset-folder, rather than simply update the path and parentId values of the associated database-row, the old row is deleted and a new one is created.

Summa summarium - having a plugin or template reference a folder by its ID is hardly safe!

What other options do we have?

Well, in addition to ID folders also have a UID. But, since that is set on row creation, that also changes when a folder is moved. So that's another no-go.

We could look it up by name - but names can be changed, so that's as unreliable as looking it up by ID (or UID).

Even if you were to write up a plugin-setting that allows you to pick the desired folder, that would - given that you move (or - if your plugin stores name rather than ID - rename) the folder - contain a null-reference.

So how can we - safely - identify a single asset-folder in a plugin, and know that it will always point to said folder and subsequently its contents?

2

Moving a folder is a pretty complex operation. You have to move all the files contained in the folder, all of the subfolders and all of the files contained in the subfolders. Another thing to consider is that a move is essentially a copy+delete.

So, how Assets goes about all of this is that firstly it mirrors the subfolder structure to be moved in the target destination. It then moves the files one by one. After that, it deletes all of the old folders.

Dividing the operation into many steps accomplishes several things: 1) It allows for displaying the progress bar. 2) It divides the processing time and memory needed across multiple requests, helping prevent timeouts 3) If the user closes the browser window, there is at least fault tolerance and no files are lost - you just get duplicates of some files and you can retry the same operation using "replace" instead of trying to figure out which files were moved and which were not.

So, the folder ID changes, because it's not the same folder anymore. Theoretically, it would be possible to manually adjust the folder IDs afterwards so that they remain unchanged, but I don't think that's a good precedent.

I could argue that folder IDs are a Craft internal thing and relying on them is not encouraged, however, I would just offer a better solution UX wise - just use an Asset source type drop down selector and a text box for the relative path. Not only it would be less amibigious than a magical ID, it would also be more consistent with user experience of addressing folders while also pointing to a specific spot, instead of an entity, which is definitely better for long-term maintenance.

  • While not really solving my issue the way I had intended to solve, I can see the reasoning behind why it is this way and will go with the "separate asset-source" for the "open" folder solution :) – Fuglsetrampen Oct 16 '17 at 7:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.