I'm trying to import nodes from my forum to drupal 7. Not in bulk, but one by one so that news posts can be created and referenced back to the forum. The kicker is that I'm wanting to bring image attachments across as well...
So far, using the code example here http://drupal.org/node/889058#comment-3709802 things mostly work: Nodes are created, but the images don't go through any validation or processing.
I'd like the attached images to be validated against the rules defined in the content type. in particular the style associated with my image field which resizes them to 600x600.
So, instead of simply creating the nodes programatically with my own form, i decided to modify a "new" node using hook_node_prepare and using the existing form to create new content (based on passed in url args). This works really well and a create form is presented pre-filled with all my data. including the image! very cute.
I expected that i could then hit preview or save and all the validation and resizing would happen to my image, but instead i get the error:
"The file used in the Image field may not be referenced."
The reason for this is that my file doesn't have an entry in the file_usage table.. *le sigh*
so, how do i get to all the nice validation and processing which happens when i manually choose a file to upload? like resizing, an entry in the file_usage table.
The ajax upload function does it, but i can't find the code which is called to do this anywhere in the api.
What file upload / validation functions does Drupal call which i'm not doing?
Anybody have any experience with the file/image api for Drupal 7 who can help me out?
For getting the usage entry (in essence, checking out a file to a specific module so that it doesn't get deleted while its in use) look up the Drupal function 'file_usage_add()'
For validating incoming images, I got this example from user.module (if you're comfortable with PHP, you can always look at the core to see how something is done the 'Drupal way'):
function user_validate_picture(&$form, &$form_state) {
// If required, validate the uploaded picture.
$validators = array(
'file_validate_is_image' => array(),
'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
);
// Save the file as a temporary file.
$file = file_save_upload('picture_upload', $validators);
if ($file === FALSE) {
form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
}
elseif ($file !== NULL) {
$form_state['values']['picture_upload'] = $file;
}
}
That function is added to the $form['#validate'] array like so:
$form['#validate'][] = 'user_validate_picture'
Related
I have a contact form that accepts a file input, I'd like to attach the file to the email that gets sent from the form.
Looking at the API reference isn't really helping, it states that the function expects a filepath with no clarification on anything beyond that.
The submit action will save a record of the into the database and this works correctly, something like:
$submission = MyDataObject::create();
$form->saveInto($submission);
$submission->write();
an Email object then gets created and sent. Both of these are functioning and working as expected.
Trying to attach the File I've tried:
$email->addAttachemnt($submission->MyFile()->Link());
which is the closest I can get to getting a filepath for the document. Dumping and pasting the resulting filepath being output by that call will download the form but that line throws an error and can't seem to locate the file.
I suspect that I'm misunderstanding what's supposed to be given to the function, clarification would be very much appreciated.
P.S. I don't currently have access to the code, I'm looking for some clarification on the function itself not an exact answer :).
In SilverStripe 4 the assets are abstracted away, so you can't guarantee that the file exists on your webserver. It generally will, but it could equally exist on a CDN somewhere for example.
When you handle files in SilverStripe 4 you should always use the contents of the file and whatever other metadata you have available, rather than relying on filesystem calls to load it.
This is how the silverstripe/userforms module attaches files to emails:
/** #var SilverStripe\Control\Email\Email $email */
$email->addAttachmentFromData(
$file->getString(), // stream of file contents
$file->getFilename(), // original filename
$file->getMimeType() // mime type
);
I would try $email->addAttachment($submission->MyFile()->Filename); If it doesn't work, you may need to prepend $_SERVER['DOCUMENT_ROOT'] to the filename.
$email->addAttachment($_SERVER['DOCUMENT_ROOT'] . $submission->MyFile()->Filename);
I have a permissions problem in Drupal. I want users to be able to create a certain node type, but there are two different paths I need to give them permissions for to let them do this. The type is content created by a module called isbn2node, and there are two ways to make content through it, each with different paths:
?=node/add/isbn2node-book
?=node/add/isbn2node_book/isbn2node
One has an underscore and the other one has a hyphen. The first path leads to a form that lets users enter information on a book manually; the second path lets them enter an ISBN, searches for it, and populates the form for them based on the results.
I've changed permissions in the People menu so they can add isbn2node-book content manually using the first path, but there isn't an option to let them use the second method. Aliasing the url so it didn't have node/add in the path didn't work either.
Creating a duplicate content type seems like an ugly solution to this; is there a more elegant way to let users access that second path?
A little code in a custom module using hook_node_access should do it.
$node is either a node object or the machine name of the content type on which to perform the access check (if the node is being created then the $node object is not available so it will be a string instead).
So this should do it:
function MY_MODULE_node_access($node, $op, $account) {
if ($op == 'create') {
$type = $node;
if($type == 'book' && $account->uid) return NODE_ACCESS_ALLOW;
}
}
I figured this out, and the issues I was having were specific to this content type. The ISBN2Node module requires users to have the Administer Nodes permission to use its lookup and bulk import features.
There is some extra code for the module's hook_permission and hook_menu sections submitted as a fix in the module's issues thread.
I am using CCF (Custom Contact Forms) plugin in which i need to have upload file field at the front end along with other fields. Max upload file size is 2MB that i defined in the plugin.
The issue is that if i try to upload bulky file (e.g 15MB) then form does not display any error and also does not upload files. The only thing happens is that the same form is just refreshed without showing any error even for other fields.
Is this the expected behavior or there is any way to come out of this?
Looking at the code to the plugin, in custom-contact-forms-front.php in function processFileUpload($field) I see:
if ($field->field_max_upload_size > 0 && $_FILES[$field->field_slug]['size'] > ($field->field_max_upload_size * 1000))
$errors[] = basename($_FILES[$field->field_slug]['name']) . __(' is too large of a file. The maximum file size for that field is ', 'custom-contact-forms') . $field->field_max_upload_size . __(' KB.', 'custom-contact-forms');
Which is horrendously cryptic, IMO, but looks like it should be putting an error message in the $errors array. Down below I see
$upload_result = $this->processFileUpload($field, $post_time);
foreach ($upload_result as $err) {
$this->setFormError($field->field_slug, $err);
So it looks like the plugin attempts to create an error message. Would have to dig into some layers to see where it's going wrong.
How can I build a block in Drupal which is able to show the node ID of the view page the block is currently sitting on?
I'm using views to build a large chunk of my site, but I need to be able to make "intelligent" blocks in PHP mode which will have dynamic content depending on what the view is displaying.
How can I find the $nid which a view is currently displaying?
Here is a more-robust way of getting the node ID:
<?php
// Check that the current URL is for a specific node:
if(arg(0) == 'node' && is_numeric(arg(1))) {
return arg(1); // Return the NID
}
else { // Whatever it is we're looking at, it's not a node
return NULL; // Return an invalid NID
}
?>
This method works even if you have a custom path for your node with the path and/or pathauto modules.
Just for reference, if you don't turn on the path module, the default URLs that Drupal generates are called "system paths" in the documentation. If you do turn on the path module, you are able to set custom paths which are called "aliases" in the documentation.
Since I always have the path module turned on, one thing that confused me at first was whether it was ever possible for the arg function to return part of an alias rather than part of system path.
As it turns out, the arg function will always return a system path because the arg function is based on $_GET['q']... After a bit of research it seems that $_GET['q'] will always return a system path.
If you want to get the path from the actual page request, you need to use $_REQUEST['q']. If the path module is enabled, $_REQUEST['q'] may return either an alias or a system path.
For a solution, especially one that involves a view argument in the midst of a path like department/%/list, see the blog post Node ID as View Argument from SEO-friendly URL Path.
In the end this snippet did the job - it just stripped the clean URL and reported back the very last argument.
<?php
$refer= $_SERVER ['REQUEST_URI'];
$nid = explode("/", $refer);
$nid = $nid[3];
?>
Given the comment reply, the above was probably reduced to this, using the Drupal arg() function to get a part of the request path:
<?php
$nid = arg(3);
?>
You should considder the panels module. It is a very big module and requires some work before you really can tap into it's potential. So take that into considderation.
You can use it to setup a page containing several views/blocks that can be placed in different regions. It uses a concept called context which can be anything related to what you are viewing. You can use that context to determine which node is being viewed and not only change blocks but also layout. It is also a bit more clean since you can move the PHP code away from admin interface.
On a side note, it's also written by the views author.
There are a couple of ways to go about this:
You can make your blocks with Views and pass the nid in through an argument.
You can manually pass in the nid by accessing the $view object using the code below. It's an array at $view->result. Each row in the view is an object in that array, and the nid is in that object for each one. So you could run a foreach on that and get all of the nid of all rows in the view pretty easily.
The first option is a lot easier, so if that suits your needs I would go with that.
New about Drupal 7: The correct way to get the node id is using the function menu_get_object();
Example:
$node = menu_get_object();
$contentType = node_type_get_name($node);
Drupal 8 has another method. Check this out:
arg() is deprecated
I'm in the progress of creating a bulk upload function for a Drupal site. Using flash I'm able to upload the files to a specific url that then handles the files. What I want to do, is not just to upload the files, but create a node of a specific type with the file saved to a filefield that has been setup with CCK. Since these are audio files, it's important that filefield handles the files, so addition meta data can be provided with the getid3 module.
Now I've looked through some of the code as I wasn't able to find an API documentation, but it's not clear at all how I should handle this. Ideally I could just pass the file to a function and just use the data returned when saving the node, but I haven't been able to find that function.
If any one has experience with this I would apreciate some pointers on how to approach this matter.
I had to do something similar some weeks ago and ended up adapting some functionality from the Remote File module, especially the remote_file_cck_attach_file() function. It uses the field_file_save_file() function from the filefield module, which might be the function you're looking for.
In my case, the files are fetched from several remote locations and stored temporarily using file_save_data(). Attaching them to a CCK filefield happens on hook_nodeapi() presave, using the following:
public static function attachAsCCKField(&$node, $filepath, $fieldname, $index=0) {
// Grab the filefield definition
$field = content_fields($fieldname, $node->type);
$validators = array_merge(filefield_widget_upload_validators($field), imagefield_widget_upload_validators($field));
$fieldFileDirectory = filefield_widget_file_path($field);
// This path does not necessarily exist already, so make sure it is available
self::verifyPath($fieldFileDirectory);
$file = field_file_save_file($filepath, $validators, $fieldFileDirectory);
// Is the CCK field array already available in the node object?
if (!is_array($node->$fieldname)) {
// No, add a stub
$node->$fieldname=array();
}
$node->{$fieldname}[$index] = $file;
}
$filepath is the path to the file that should be attached, $fieldname is the internal name of the filefield instance to use within the node and $index would be the 0 based index of the attached file in case of multiple field entries.
The function ended up within a utility class, hence the class syntax for the verifyPath() call. The call just ensures that the target directory is available:
public static function verifyPath($path) {
if (!file_check_directory($path, FILE_CREATE_DIRECTORY)) {
throw new RuntimeException('The path "' . $path . '" is not valid (not creatable, not writeable?).');
}
}
That did it for me - everything else happens on node saving automatically.
I have not used the getid3 module yet, so I have no idea if it would play along with this way of doing it. Also, I had no need to add additional information/attributes to the filefield, so maybe you'd have to put some more information into the field array than just the file returned by field_file_save_file(). Anyways, hope this helps and good luck.
I have done something whith imagefield which worked, I think the structure has to be right otherwise it won't work. It took a lot of trial and error. This is is what I populated the imagefield with.
$image['data'] =array(
'title' => $media_reference_attributes->getNamedItem("source")->value,
'description' => $description,
'alt' => "",);
$image['width'] = $width;
$image['height'] = $height;
$image['mimetype'] = $mime_type
$image['uid'] = 1;
$image['status'] = 1;
$image['fid'] = $fid;
$image['filesize'] = $file->filesize;
$image['nid'] = $id;
$image['filename'] = $url;
$image['timestamp'] = $file->timestamp;
$image['filepath'] = $file_path;
Hope this is of some help.
You might want to look at Image FUpload if you need a look at integrating the flash upload.
To push the files on to another server while still handling them through Drupal sounds a little like the CDN space, maybe look at the behavior in the CDN or CDN2 projects?
If you find a clear solution please come back and post it!