
Component Dropbox File Source for MODX Revolution
To implement one project, it became necessary to use some kind of cloud storage. The bottom line is that there are several distributed employees, each of whom uses a special program, the result of which are separate XML files. The data of these files is necessary in order to generate reports on the site, where users could download the information available to them. The problem is that employees work on their local machines and do not interact with the Internet (that is, they do not use a single server or something like that). And so I decided to use Dropbox, like I’ll configure each user my daddy where their files will be synchronized, and on the side of the site I’ll take everything from the dropbox and use it to generate reports. I'll tell you under the cut
In general, initially I thought that everything would be much simpler, since quite a while I came across a ready-made component that installs a file source in MODX that interacts with Dropbox, but when I installed it, I received only a bunch of fatal errors. The component was developed in 2012, and either used the old Dropbox PHP SDK, or something was generic at all, but in any case it did not work at all. In the end, it was clear that everything would have to be rewritten. I did not find any special examples on the network, but the dropbox pleases with pretty solid documentation here and here. As a result, I took the file source object in the package as a basis, uploaded the latest version of the PHP SDK (now it is 1.1.4) and finished it to the point where you could manage files in the dropbox through the site admin panel.

This completed the development of the dropbox-2.0.0-beta package. But the thought did not give rest that I still have no opportunity to receive data from the dropbox of the changes. Just as I understand it, I will have to deal with tens of thousands of documents in the end, and I can’t just go through the folders every time and check the revisions on the site side (by the way, at once the dropbox using the Client :: getMetadataWithChildren ($ path ) returns no more than 2000 records, although 25000 are specified in the method). Digging through the docks, I got to the Client :: getDelta method ($ cursor = null, $ pathPrefix = null). This is exactly what we need, since passing a known cursor into it, you can get information about the changes since its inception. But here is a little nuisance: how to get the last cursor? The fact is that if a dropbox account has already existed for a long time, a lot of changes can accumulate in it throughout the history, and by simply sorting the cursors you can get to the actual one for a very long time. Interestingly, there is no such method in the PHP SDK, although the API itself has a method for this . Well, okay, if there is a method in the kernel, then do not finish it for a long timeyour client class to be able to receive this information. Now you can fix a starting point for yourself and monitor the changes without any sorting. When I got all this, it became obvious to me that it would be convenient to store this data in a database, and to transfer some specialized dropbox client methods to specific entities. Next, I will simply show some examples of using what happened.
Of course, before you do anything, you need to register your Dropbox application (of course, you must be registered with Dropbox ).
After installing the Dropbox package , a new type of file sources appears in the system - Dropbox. Create a media resource with this type.
If everything is OK, then after saving the file source should show the contents of your dropbox (see the first picture above).
The first thing I did in the updated version of the package was the opportunity to get the Dropbox client in a separate media resource method. You can get it, for example, like this:
This is convenient because you can have any number of media resources and bother with their settings, while each media resource will work with its dropbox folder.
Two steps are needed here:
In general, if you dig through the official documentation, you can do a lot of things on the basis of this. In general, there is a desire to develop a file manager component for MODX that could exchange files between different types of media resources, but so far there is no time / resources for this.
You can download the package from the off-site modx.com
Project on the github: github.com/Fi1osof/modx-Dropbox
And finally, a small note about one insidious problem that I encountered during the development of the component.
UPD: In the process, a couple of points were found out:
1. Dropbox PHP SDK requires PHP at least 5.3
2. It seems that it requires a 64-bit axis. The discussion is here .
In general, initially I thought that everything would be much simpler, since quite a while I came across a ready-made component that installs a file source in MODX that interacts with Dropbox, but when I installed it, I received only a bunch of fatal errors. The component was developed in 2012, and either used the old Dropbox PHP SDK, or something was generic at all, but in any case it did not work at all. In the end, it was clear that everything would have to be rewritten. I did not find any special examples on the network, but the dropbox pleases with pretty solid documentation here and here. As a result, I took the file source object in the package as a basis, uploaded the latest version of the PHP SDK (now it is 1.1.4) and finished it to the point where you could manage files in the dropbox through the site admin panel.

This completed the development of the dropbox-2.0.0-beta package. But the thought did not give rest that I still have no opportunity to receive data from the dropbox of the changes. Just as I understand it, I will have to deal with tens of thousands of documents in the end, and I can’t just go through the folders every time and check the revisions on the site side (by the way, at once the dropbox using the Client :: getMetadataWithChildren ($ path ) returns no more than 2000 records, although 25000 are specified in the method). Digging through the docks, I got to the Client :: getDelta method ($ cursor = null, $ pathPrefix = null). This is exactly what we need, since passing a known cursor into it, you can get information about the changes since its inception. But here is a little nuisance: how to get the last cursor? The fact is that if a dropbox account has already existed for a long time, a lot of changes can accumulate in it throughout the history, and by simply sorting the cursors you can get to the actual one for a very long time. Interestingly, there is no such method in the PHP SDK, although the API itself has a method for this . Well, okay, if there is a method in the kernel, then do not finish it for a long timeyour client class to be able to receive this information. Now you can fix a starting point for yourself and monitor the changes without any sorting. When I got all this, it became obvious to me that it would be convenient to store this data in a database, and to transfer some specialized dropbox client methods to specific entities. Next, I will simply show some examples of using what happened.
Register an API application.
Of course, before you do anything, you need to register your Dropbox application (of course, you must be registered with Dropbox ).
In detail
To do this, go to the page www.dropbox.com/developers/apps and click Create app (By the way, the name of the application must be unique for the entire Dropbox (since it is possible to publish public applications, so it’s better to specify the domain of the site or something for names like myApp, etc. are busy and dropbox will not let you save)). The types of applications being created are two Drop-ins app and Dropbox API app , we will create the second.

Here, we’ll immediately take a closer look at step 3.
Can your app be limited to its own folder?
If you select "My app only needs access to files it creates.", Then the application will create its own folder, where the application will have access. I have this folder Applications / [AppName]. That is, the Applications folder is the system folder for all applications, and then for each application its own folder is created.
And if you select "My app needs access to files already on Dropbox.", The application will gain access to the root folder and then the list of available files will be limited to only the selected file types. That is, if you select this item, a new step appears What type of files does your app need access to? and there you can select either “All file types” (that is, all files) or “Specific file types” and indicate which file types are available.

After we clicked “Create App”, the application will be created and the application settings page will open. On it, among other things, we will find the App key and App secret , but we will not need them yet, we will consider their use later. In the meantime, we are interested in Access token . We will generate it and copy it somewhere in an inaccessible place. You can’t see him again. True, you can generate a new token, and interestingly, the previous ones will work. I generated three tokens and they all work, and I can’t see the list of used tokens and cancel unnecessary tokens, I can only delete the entire application. Katz is not a bit secrete, but this is more a feature than a bug.


Here, we’ll immediately take a closer look at step 3.
Can your app be limited to its own folder?
If you select "My app only needs access to files it creates.", Then the application will create its own folder, where the application will have access. I have this folder Applications / [AppName]. That is, the Applications folder is the system folder for all applications, and then for each application its own folder is created.
And if you select "My app needs access to files already on Dropbox.", The application will gain access to the root folder and then the list of available files will be limited to only the selected file types. That is, if you select this item, a new step appears What type of files does your app need access to? and there you can select either “All file types” (that is, all files) or “Specific file types” and indicate which file types are available.

After we clicked “Create App”, the application will be created and the application settings page will open. On it, among other things, we will find the App key and App secret , but we will not need them yet, we will consider their use later. In the meantime, we are interested in Access token . We will generate it and copy it somewhere in an inaccessible place. You can’t see him again. True, you can generate a new token, and interestingly, the previous ones will work. I generated three tokens and they all work, and I can’t see the list of used tokens and cancel unnecessary tokens, I can only delete the entire application. Katz is not a bit secrete, but this is more a feature than a bug.

File Source Setting
After installing the Dropbox package , a new type of file sources appears in the system - Dropbox. Create a media resource with this type.
In detail

When you created the file source, open it for editing and specify the Access Token application.



When you created the file source, open it for editing and specify the Access Token application.

If everything is OK, then after saving the file source should show the contents of your dropbox (see the first picture above).
Dropbox client
The first thing I did in the updated version of the package was the opportunity to get the Dropbox client in a separate media resource method. You can get it, for example, like this:
$source_id = 27; // ID вашего источника файлов
$source = $modx->getObject('modMediaSource', $source_id);
$client = $source->getClient();
This is convenient because you can have any number of media resources and bother with their settings, while each media resource will work with its dropbox folder.
Get information about the contents of the directory
$source_id = 27; // ID вашего источника файлов
$source = $modx->getObject('modMediaSource', $source_id);
$client = $source->getClient();
$result = $client->getMetadataWithChildren('/');
print_r($result);
Result
Array
(
[hash] => cfcf0b65c94cff03c32390b3c30a5812
[thumb_exists] =>
[bytes] => 0
[path] => /
[is_dir] => 1
[icon] => folder
[root] => dropbox
[contents] => Array
(
[0] => Array
(
[rev] => 115ce031c0d71
[thumb_exists] => 1
[path] => /315a73ec24 - копия.jpg
[is_dir] =>
[client_mtime] => Fri, 05 Dec 2014 23:12:30 +0000
[icon] => page_white_picture
[bytes] => 258713
[modified] => Mon, 08 Dec 2014 02:45:31 +0000
[size] => 252.6 KB
[root] => dropbox
[mime_type] => image/jpeg
[revision] => 71118
)
[1] => Array
(
[rev] => 102d6031c0d71
[thumb_exists] => 1
[path] => /315a73ec24.jpg
[is_dir] =>
[client_mtime] => Fri, 05 Dec 2014 23:12:30 +0000
[icon] => page_white_picture
[bytes] => 258713
[modified] => Sat, 06 Dec 2014 21:21:20 +0000
[size] => 252.6 KB
[root] => dropbox
[mime_type] => image/jpeg
[revision] => 66262
)
)
[size] => 0 bytes
)
Get the contents of the file
$source_id = 27; // ID вашего источника файлов
$source = $modx->getObject('modMediaSource', $source_id);
$content = $source->getContent('/315a73ec24.jpg');
Or so
$source_id = 27; // ID вашего источника файлов
$entry = $modx->newObject('DropboxEntry', array(
"source_id" => $source_id,
"path" => '/315a73ec24.jpg',
));
$content = $entry->getContent(); // Или $entry->get('content');
Or so
$source_id = 27; // ID вашего источника файлов
$source = $modx->getObject('modMediaSource', $source_id);
$entry = $modx->newObject('DropboxEntry', array(
"path" => '/315a73ec24.jpg',
));
$entry->Source = $source;
$content = $entry->getContent(); // Или $entry->get('content');
Or so (if the record is already in the database)
$entry = $modx->getObject('DropboxEntry', array(
"path" => '/315a73ec24.jpg',
));
$content = $entry->getContent(); // Или $entry->get('content');
Track changes in sections
Two steps are needed here:
1. Get the current cursor for the section and save it in the database
In general, it is not necessary to save it, but it’s so convenient, it won’t go anywhere.
$source_id = 27; // ID вашего источника файлов
$cursor = $modx->newObject('DropboxCursor', array(
"source_id" => $source_id,
"path" => '/',
));
if($result = $cursor->getLast()){
$cursor->fromArray($result);
$cursor->save();
}
2. Request changes.
$cursor= $modx->getObject('DropboxCursor', array(
"path" => '/',
));
$result = $entry->getDelta();
print_r($result);
Answer
Array
(
[has_more] =>
[cursor] => AAE3sefSDffe3SiOcfkaMd7vyzjQvjxngkI1gkJGLvBQplsNUhF9tx5Okb7epnGufIziuDWjyG16sWaxjRcnt-XjT-jBD_8fDW89enF7OO3AHBjsZz9vHTBJenmeCdLUgO0f-EqRJYigzELD0rzD3hFNn-YGfDQaxUOs0bHd2F5qND3J6HX-HwOqOLWQfcbuMZMNHN1_UGN2VODIbaPzBbML0rap_B6ibV03JQxtiGHZtxwjP-mSw8drigK3yJtvqyR3XdzHP5uVsyrD8gkyGk1J9dOTLdzFRA-woImCg1Iwc9XA7l1XsZGCRvDYpXjg
[entries] => Array
(
)
[reset] =>
)
If there are changes, then you will see them in the entries array .File revisions
$entry = $modx->getObject('DropboxEntry', array(
"path" => '/315a73ec24.jpg',
));
$result = $entry->getRevisions();
And you can restore the desired version of the file.
$entry = $modx->getObject('DropboxEntry', array(
"path" => '/315a73ec24.jpg',
));
$result = $entry->restoreFile('102d6031c0d71');
In general, if you dig through the official documentation, you can do a lot of things on the basis of this. In general, there is a desire to develop a file manager component for MODX that could exchange files between different types of media resources, but so far there is no time / resources for this.
You can download the package from the off-site modx.com
Project on the github: github.com/Fi1osof/modx-Dropbox
And finally, a small note about one insidious problem that I encountered during the development of the component.
UPD: In the process, a couple of points were found out:
1. Dropbox PHP SDK requires PHP at least 5.3
2. It seems that it requires a 64-bit axis. The discussion is here .