Renaming Rackspace Folder/Container - php

I have the PHP library from Rackspace. We keep all files in a Container called 'data'. Within that container is a hierarchical directory of files.
I am able to rename or move an object, no problem (wrapped in my own class):
$this->container->move_object_to('uploads/files/file.txt', 'data', 'uploads/files2/filecopy.txt');
But I'm not able to do the same with a folder:
$this->container->move_object_to('uploads/files', 'data', 'uploads/files2');
So I thought instead, I'd get all objects in a folder and copy each individually. But I'm only able to get objects in a container:
$container = $this->connection->get_container('data');
$files = $container->list_objects();
this doesn't work:
$container = $this->connection->get_container('data/uploads');
$files = $container->list_objects();
How can I rename a folder? Or alternatively, move all objects in a folder to a new one?

The issue here is that there is no such thing as a folder inside of a container. The container is the top-level grouping, and under that is just a set of objects.
Your objects have directory separators in their names so that they can be referred to that way in URLs. In reality, they are just individual objects with similar prefixes in their names; they are not actually grouped "by folder".
I'm not a PHP programmer, but here's some pseudocode (may not be exact):
Edited to use function provided by #magglass1
$old_dir = "oldir/";
$new_dir = "newdir/";
$container = $this->connection->get_container('data');
$files = $container->list_objects(0, NULL, $old_dir);
foreach ($files as $file) {
$new_filename = substr_replace($file, $new_dir, strpos($file, $old_dir), strlen($old_dir));
$this->container->move_object_to($file, 'data', $new_filename);
};

You can list objects by pseudo folder by specifying a prefix in your list_objects() call. Here is the usage of the function:
list_objects($limit=0, $marker=NULL, $prefix=NULL, $path=NULL)
So something along the lines of this should work:
$container = $this->connection->get_container('data');
$files = $container->list_objects(0, NULL, 'uploads/');
You'd then loop through and copy all the returned objects.
-Mark

Related

Automatically loading the classes

I've built "core" class that loads another classes, and I want to load automatically all the classes in spesific folder named "class", I've started to build something, but I have no idea if it's good.
In the construct function at the core class, I'm getting an array with the class names to load.
The construct function calls to function named _loadClasses, and in the _loadClasses function, I'm loading the classes by using require_once() fucntion.
Then at the top of the page, i'm adding public variable with the name of the class.
For example, "public $example;"
Now, what left is to create the ocject of the class, so that's what I did.
Example of the _loadClasses method:
require_once("class/user.class.php");
self::$user = new User();
Here comes the "automat" part.
I want the function _loadClasses to get an array, for example:
private function _loadClasses( $classesToLoad = array('security', 'is') );
and now, I'm using glob to load the classes from the folder "class", the name syntax of the classes files in the folder "class" is classname.class.php.
$classesArray = array(); // initialize the variable of all the web classes
$classesFiles = glob("class/*.php"); // gets all the web classes from the folder 'class'
foreach($classesFiles as $file) { // loop on the classes in the folder 'class'
$filename = explode('class/', $file);
$filename = $filename[1];
$className = explode('.class.php', $filename);
$className = $className[0];
if($className != 'index.php' || $className != 'database') {
array_push( $classesArray, $className ); // adds the class name into the array 'classesArray'
}
}
foreach( $classesArray as $className ) {
if( in_array($className, $classesToLoad) ) {
require_once("class/$className.class.php");
$classLines = file( "class/$className.class.php" );
$classNameLine = $classLines[1];
$classNameLine = explode(' ', $classNameLine);
$classObjectName = $classNameLine[1];
$classObjectName = explode(" ", $classObjectName);
self::$$classObjectName = new $classObjectName();
}
}
I need something like that, of curse it doesn't work, it's just to show you what I wanna do with an example. Thanks in advance.
For this particular approach I'd suggest something like:
// Your custom class dir
define('CLASS_DIR', 'class/')
// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);
// You can use this trick to make autoloader look for commonly used "My.class.php" type filenames
spl_autoload_extensions('.class.php');
// Use default autoload implementation
spl_autoload_register();
To get started there's no need to implement a parent class autoloading functionality for "core" objects since they should only be aware of their role functionality. Use php standard library.
For this purposes you can use the __autoload() function. It will be called when you create a new object.
__autoload($class)
{
require 'dir/to/your/classes/'. $class. '.php'
}
You have to use one class per file and name the files the same as the class they describe.
"it doesn't work" is not a useful diagnostic. What doesn't work? What's the error message? Which line does it fail at? Looking at the code, the first loop, though a little messy (why do you have a file named index.php in this directory? Why don't you just glob for *.class.php?) should probably work OK. But the second loop is horrible.
To start with, why load all the filenames into an array in one loop, then use a second loop to load some of them? As for reading the class file to determine the object name....words fail me. Simply name it as the filename without the .class.php
$classesFiles = glob("class/*.class.php"); // gets all the web classes from the folder 'class'
foreach($classesFiles as $file) {
$prefix=array_shift(explode('.', basename($file)));
if (in_array($prefix, $classestoload)
&& !isset($this->$prefix)) {
if (!class_exists($prefix)) {
require($file);
}
$this->$prefix=new $prefix();
}
}
You could use the autoloader, but this will get messy if you integrate with other code which also uses the autoloader, but in a different way.

Azure PHP SDK: get the asset by asset name

Is it possible to get the asset details using asset name with Azure PHP sdk. I can get all the asset list, but it's loading first 1000 assets only.
getAssetList();
I can get single asset details using asset id.
getAsset($asset);
But in my case, I don't have asset id with me. I just have asset name alone. Now how do I get the asset details using this?
EDIT:
I got some help from Azure support saying that, we can use $skip parameter for pagination. I got code snippet in c#
for (int i = 0; i < _context.Assets.Count(); i += 1000 )
{
var assets = _context.Assets.Skip(i);
foreach (IAsset objIAsset in assets)
{
Console.WriteLine(objIAsset.Name.ToString());
}
}
How can I use this param in PHP SDK.
It seem that Azure SDK for PHP don't support skip method. However, I used the fiddler to monitor C# skip method and got the URL like this:
https://***-hs.cloudapp.net/api/Assets()?$skip=1000
So I think we can bulid up the request path like above in our PHP project and we can modify the getAssetList method in "MediaServicesRestProxy" file.
I add a function named "getAssetListBySkip($number)" into "MediaServicesRestProxy" class, the code like this:
/**
* Get asset list using skip number
*
* */
public function getAssetListBySkip($number)
{
$propertyList = $this->_getEntityList("Assets()?".'$skip='.$number);
$result = array();
foreach ($propertyList as $properties) {
$result[] = Asset::createFromOptions($properties);
}
return $result;
}
We can call this method like this:
$mediaServiceProxy = ServicesBuilder::getInstance()->createMediaServicesService(
new MediaServicesSettings("**","**/**="));
$result=$mediaServiceProxy->getAssetListBySkip(1000);
Azure Media services supports filtering by name. You can construct web request to be like
/api/assets()?$filter=Name%20eq%20'Your Name'&$top=1
You can also filter by other properties
Have you tried REST API that are used when creating, processing, managing, and delivering Assets. https://msdn.microsoft.com/en-us/library/azure/hh974277.aspx#list_an_asset but I do think we can list asset via a name directly since id is an unique indentifier of asset entity. PHP Azure SDK leverages assetId to get an Asset as well:
public function getAsset($asset)
{
$assetId = Utilities::getEntityId(
$asset,
'WindowsAzure\MediaServices\Models\Asset'
);
return Asset::createFromOptions($this->_getEntity("Assets('{$assetId}')"));
}
But in my case, I don't have asset id with me. I just have asset name
alone. Now how do I get the asset details using this?
Here are some test function code snippets for your reference:
public function testListAllAssets(){
// Setup
$asset1 = new Asset(Asset::OPTIONS_NONE);
$asset1->setName(TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix());
$asset2 = new Asset(Asset::OPTIONS_NONE);
$asset2->setName(TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix());
// Test
$asset1 = $this->createAsset($asset1);
$asset2 = $this->createAsset($asset2);
$result = $this->restProxy->getAssetList();
// Assert
$this->assertCount(2, $result);
$names = array(
$result[0]->getName(),
$result[1]->getName()
);
$id = array(
$result[0]->getId(),
$result[1]->getId()
);
$this->assertContains($asset1->getName(), $names);
$this->assertContains($asset2->getName(), $names);
$this->assertContains($asset1->getId(), $id);
$this->assertContains($asset2->getId(), $id);
}
public function testGetAnAssetReference(){
// Setup
$assetName = TestResources::MEDIA_SERVICES_ASSET_NAME . $this->createSuffix();
$asset = new Asset(Asset::OPTIONS_NONE);
$asset->setName($assetName);
$asset = $this->createAsset($asset);
// Test
$result = $this->restProxy->getAsset($asset);
// Assert
$this->assertEquals($asset->getId(), $result->getId());
$this->assertEquals($asset->getName(), $result->getName());
}
From: https://github.com/Azure/azure-sdk-for-php/blob/master/tests/functional/WindowsAzure/MediaServices/MediaServicesFunctionalTest.php
According to my testing, it seems that we can’t use Asset’s name to get the information of asset in Media Service.
$mediaServiceProxy = ServicesBuilder::getInstance()->createMediaServicesService(
new MediaServicesSettings("**","******"));
$asset = new Asset(Asset::OPTIONS_NONE);
$asset->setName('For-Test-wmv-Source');
//$asset don't have the value of id,
// unless execute ‘createAsset($asset)’, "$asset1" will be set the ID
$asset1 =$mediaServiceProxy->createAsset($asset);
$result2=$mediaServiceProxy->getAsset($asset1);
PHP SDK support the method named “getAsset($asset)”. Actually, the method get the Asset information by Asset id, just like the Aka's reference code.And Azure REST API don’t support the method queried by Asset’s name.
Please refer to the official document.
Alternative approach is that you can store your assets information (such as Id,URl,name and ect.) into Azure table storage when you upload them into media service. If you want to use it, you can fetch and filter the data of Asset’s name you wants from table storage.

set upload folder in dataobject to the title of the related page - Silverstripe 3.1

hi i've got a gallery page. this gallery page has a gallery image object with an has_many relation.
private static $has_many = array(
'GalleryImages' => 'GalleryObject'
);
my gallery object has an image upload field. I want to set the upload folder to the title of the gallery page
i tried this with no result
$visual->setFolderName('Galerie/'.$this->Gallery()->Title);
and this (what i would prefer)
public function getGalleryTitle() {
$galleryTitle = $this->Gallery()->Title->First();
$uploadFolder = str_replace(' ', '-', $this->$galleryTitle);
return $uploadFolder;
}
$visual->setFolderName('Galerie/'.$this->$uploadFolder);
the second returns and error (undefined variable uploadFolder ?!) and my upload folder is now set to "Galerie/DataList"
can someone tell me how to convert the output of $uploadFolder so that i get back the title?
EDIT:
GalleryHolder: http://www.sspaste.com/paste/show/5267dea3579a6
GalleryPage: http://www.sspaste.com/paste/show/5267dee4c9752
GalleryObject: http://www.sspaste.com/paste/show/5267df0af1a65
you where almost there..
Here is your edited getGalleryTitle() function.
It is basically checking if the GalleryObject has a parent Gallery via $this->GalleryID. Since it is a has_one relation the column will be named GalleryID.
Then we get the Gallery object with $this->Gallery() and get it's title with $gallery->Title.
I've also replaced your str_replace with SilverStripe's URLSegmentFilter class. Which will removed spaces and other special characters non welcome in URL, a better solution.
public function getGalleryTitle()
{
if ( $this->GalleryID )
{
$gallery = $this->Gallery();
$filter = new URLSegmentFilter();
return $filter->filter( $gallery->Title );
}
else{
return 'default';
}
}
Then in the getCMSFields() function, when creating your UploadField we just call the getGalleryTitle() function that returns the string for the folder name.
$visual = new UploadField('Visual', _t('Dict.IMAGE', 'Image'));
$visual->setFolderName('Galerie/'.$this->getGalleryTitle());
A few notes..
$this references the current Object instance, so you can't use $this->$galleryTitle to access a variable you just created in your function, $galleryTitle by itself is enough.
You were calling $this->$uploadFolder in setFolderName, this doesn't work for the same reason, and also, using $uploadFolder by itself wouldn't work since this variable was created in the scope of another function. So we just call the function we defined on our Object with $this->getGalleryTitle() since it returns the value we want.
This should work fine, but keep in mind that if the Title of the Gallery changes at some point, the folder name will change too. So you might end up with images uploaded in many different folders for the same gallery... I personally wouldn't advise it, unless you implement some kind of "Title locking system" or some way to keep the "correct" or first "valid/acceptable" Gallery title in a separate object property that can't be edited and use this in the folder name.
I usually only use the ID in those case ($gallery->ID), as this will not change.
edit
Another version of getGalleryTitle() that should work even if the GalleryObject isn't saved yet.
public function getGalleryTitle()
{
$parentID = Session::get('CMSMain')['currentPage'];
if ( $parentID )
{
$gallery = Page::get()->byID( $parentID );
$filter = new URLSegmentFilter();
return $filter->filter( $gallery->Title );
}
else{
return 'default';
}
}
First, I check to see whether we're on the CMSSettingsPage or in a ModelAdmin page (Should you be using them). You want to get all the information about which class the controller is managing as it's data record. (If you have firebug, FB($this) in getCMSFields() on the related DataObject (DO) will show you the page managed under DataRecord)
Controller::curr()->currentPage() will get you the current page the DO is being managed on, and ->URLSegment will get the page url name, though you could use Title or MenuTitle also.
Here is an example which will set up a folder underneath assets/Headers to save images in. Running this on the HomePage (ie URL Segment 'home') will create and save objects into the folder /assets/Headers/home.
if (Controller::curr()->class == 'CMSSettingsController' || Controller::curr() instanceof Modeladmin) {
$uploadField->setFolderName('Headers');
}
else
{
$uploadField->setFolderName('Headers/' . Controller::curr()->currentPage()->URLSegment);
}

How to Zip mutiple files using Zend Compress Filter?

I have multiples files to be compressed into one unique file (zip), but it seems that it creates a new file everytime the loop restart, how do I do that? there is no enough documentation about this, here is my code:
$file1 = "test1.xls";
$files2 = array(
"test2.xls", "test3.xls"
);
$filter = new Zend_Filter_Compress(array(
'adapter' => 'Zip',
'options' => array(
'archive' => BASE_PATH .'/public/' . $this->configuracoes->get('media') . '/temp/zipped'.date('d-m-Y-H-i-s').'.zip'
)
));
$compress = $filter->filter($file1);
foreach($files2 as $file){
$compress = $filter->filter($file);
}
This only result a zip with test3.xls inside.
Worth looking at this link, seems to be the same answer where you open the zip, add files, then close it outside the loop.
Create zip with PHP adding files from url
An old question but I found this looking for something similar.
You can pass a directory to the filter function and it will recursively add all files within that directory.
i.e
$compress = $filter->filter('/path/to/directory/');

How do we iterate over the object that implements iterator

Iam rendering a menu (using Zend framework) (zend_navigation)
what iam doing is getting the page as label if the page has the value "myPage"
than then iam setting the new URI with the page as expected
$it = new RecursiveIteratorIterator(
$container, RecursiveIteratorIterator::SELF_FIRST);
foreach ($it as &$page) {
$label = $page->label;
if($label = "MyPage"){
$newuri = "mypage.php?stcode=".$stcode."&cde=".$cde;
$page->setUri($newuri);
}
}
In the above statement iam getting an error
"An iterator cannot be used with foreach by reference".
I want to use reference so that based on the label i can point the page to new uri
Now my problem and all the menu items in the menu are getting the same URI .
Does it work without the & ? Objects are passed by reference by default in PHP, so calling setUri should (in theory) modify the original object. Also note that your if statement is doing an assignment ($label = "MyPage") rather than a comparison ($label == "MyPage").
Assuming $container is your Zend Navigation object, the component has methods to make this easier anyway, so you should be able to simplify your code to:
$page = $container->findByLabel('MyPage');
$page->setUri("mypage.php?stcode=".$stcode."&cde=".$cde);
See http://framework.zend.com/manual/en/zend.navigation.containers.html#zend.navigation.containers.finding for some more examples.

Categories