How to get file object from file path in Concrete5? - concrete5

I want to get thumbnail from the file inside the themes directory but getThumbnail() function requires me to pass a file object.
This obviously doesn't work:
$v = View::getInstance();
$themePath = $v->getThemePath();
$thumbnail = $imageHelper->getThumbnail($themePath.'/images/abc.jpg', 100, 100, true);
So is it possible to get file object from the file path?

If the file exists only in the folder structure but not as concrete5 File Object, you need the FileImporter first:
use Concrete\Core\File\Importer;
$fi = new Importer();
if($fv = $fi->importIncomingFile($themePath . '/' . $filename)){
$returnFile = \Concrete\Core\File\File::getByID($fv->getFileID());
}
Then you may pass that file object to the getThumbNail() function. The getThumbNail() doesn't take a path but an image object as first parameter:
$imageHelper = Core::make('helper/image');
$thumbnail = $imageHelper->getThumbnail($returnFile, 300, 9999, false);
Here are all params that are taken (from the API):
/**
* Returns a path to the specified item, resized and/or cropped to meet max width and height. $obj can either be
* a string (path) or a file object.
* Returns an object with the following properties: src, width, height
* #param mixed $obj
* #param int $maxWidth
* #param int $maxHeight
* #param bool $crop
*/
public function getThumbnail($obj, $maxWidth, $maxHeight, $crop = false)

Related

Create file dynamically as File object and then publish

It's evidently a little more complicated to create a file dynamically in SS4
$folder = Folder::find_or_make('Cards');
$filename = 'myimage.jpg';
$contents = file_get_contents('http://example.com/image.jpg');
$pathToFile = Controller::join_links(Director::baseFolder(), ASSETS_DIR, $folder->Title, $filename);
file_put_contents($pathToFile, $contents);
$image = Image::create();
$image->ParentID = $folder->ID;
$image->Title = "My title";
$image->Name = $filename;
$image->FileFilename = 'Cards/' . $filename;
$image->write();
Member::actAs(Member::get()->first(), function() use ($image, $folder) {
if (!$image->isPublished()) {
$image->publishFile();
$image->publishSingle();
}
if (!$folder->isPublished()) {
$folder->publishSingle();
}
});
The above, creates the file as expected in /assets/Cards/myimage.jpg and publishes it fine
However all previews are blank, so it's obviously not finding the file:
Any idea what I missed in creating the Image object?
This should work:
$folder = Folder::find_or_make('Cards');
$contents = file_get_contents('http://example.com/image.jpg');
$img = Image::create();
$img->setFromString($contents, 'image.jpg');
$img->ParentID = $parent->ID;
$img->write();
// This is needed to build the thumbnails
\SilverStripe\AssetAdmin\Controller\AssetAdmin::create()->generateThumbnails($img);
$img->publishSingle();
FYI: $img->Filename no longer exists. An Image or File object have a File property, which is a composite field of type DBFile. This composite fields contains the filename, hash and a variant…
So you should use the composite field to address these fields.

How to remove query string from static resource?

I've tried it with
https://www.drupal.org/project/remove_querystring_from_static_resource
But it doesn't work well for me .
How can I achieve that programmatically?
The following is the test result:
This trouble is usually encountered when static resources (eg. images, css & javascript files) are accessed using a query string.
Eg: http://example.com/image.png?something=test
Those query strings are used for avoiding browser caching. Their values are changed, so the browser should do a new request instead of getting cached resource.
You should remove those query strings (?something=test in my example) and use some suitable Cache-Control headers.
Edit:
Try this code.
Replace THEMENAME with your theme name.
/**
* Implements template_process_html().
* Remove Query Strings from CSS & JS filenames
*/
function THEMENAME_process_html( &$variables) {
$variables['styles'] = preg_replace('/\.css\?[^"]+/', '.css', $variables['styles']);
$variables['scripts'] = preg_replace('/\.js\?[^"]+/', '.js', $variables['scripts']);
}
/**
* Implement hook_image_style
* Override theme image style to remove query string.
* #param $variables
*/
function THEMENAME_image_style($variables) {
// Determine the dimensions of the styled image.
$dimensions = array(
'width' => $variables['width'],
'height' => $variables['height'],
);
image_style_transform_dimensions($variables['style_name'], $dimensions);
$variables['width'] = $dimensions['width'];
$variables['height'] = $dimensions['height'];
// Determine the URL for the styled image.
$variables['path'] = image_style_url($variables['style_name'], $variables['path']);
// Remove query string for image.
$variables['path'] = preg_replace('/\?.*/', '', $variables['path']);
return theme('image', $variables);
}
Finally I solved the issue with this code:
use Drupal\Core\Asset\AttachedAssetsInterface;
/**
* Implements hook_css_alter().
*/
function bootstrap_css_alter(&$css, AttachedAssetsInterface $assets){
foreach ($css as &$file) {
if ($file['type'] != 'external') {
$file['type'] = 'external';
$file['data'] = '/' . $file['data'];
}
}
}
/**
* Implements hook_js_alter().
*/
function bootstrap_js_alter(&$javascript, AttachedAssetsInterface $assets){
foreach ($javascript as &$file) {
if ($file['type'] != 'external') {
$file['type'] = 'external';
$file['data'] = '/' . $file['data'];
}
}
}
Put this code to your yourthemename.theme file.
it works perfect on drupal 8
Hope this help you guys.

How to show content of a custom block using PHP code format in Drupal 8

I have added some custom code in a block using PHP code format to show that block on a specific page. I have checked all the things working fine on Devel PHP page but contents are not showing on page. The code below fetches the field value of a destination node.
$refer = $_SERVER[HTTP_REFERER];
$parsed = parse_url($refer);
$alias = array_pop($parsed);
$dst = \Drupal::service('path.alias_manager')->getPathByAlias($alias , $langcode);
$nid = array_pop(explode('/', $dst));
$dest_node = node_load($nid);
$body = $dest_node->get('body')->getValue();
print $body; //have tried other printing methods also but invain
Hope this clarifies the question.
Thanks
Are you sure that it works in Devel? I've just tried to execute your code, and this line:
$body = $dest_node->get('body')->getValue();
returns Array.
Try to use this one instead:
$body = $dest_node->body->value;
First of all, your first block of code (getting current node) can be replaced with just one line:
$node = \Drupal::service('current_route_match')->getParameter('node');
And the whole block can be changed in the following way:
if ($node = \Drupal::service('current_route_match')->getParameter('node')) {
print $node->body->value;
}
P.S. And it's definitely a bad idea to use PHP text filter. You may easily write your own custom module providing required block. The simplest block plugin requires several lines of code:
/**
* #file
* Contains \Drupal\my_module\Plugin\Block\MyBlock.
*/
namespace Drupal\my_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides my super block.
*
* #Block(
* id = "my_module_block",
* admin_label = #Translation("My Block"),
* category = #Translation("My Module"),
* )
*/
class MyBlock extends BlockBase{
/**
* Builds and returns the renderable array for this block plugin.
*
* #return array
* A renderable array representing the content of the block.
*
* #see \Drupal\block\BlockViewBuilder
*/
public function build() {
if ($node = \Drupal::service('current_route_match')->getParameter('node')) {
return [ '#markup' => $node->body->value ];
}
}
}
This file MyBlock.php must be placed in /src/Plugin/Block/ directory inside your custom module named my_module.

Concrete5 5.7: Using file objects in a Single Page Controller

I try to attach a file object to a mail object.
I have included the following in the form of my view:
$f = new Concrete\Core\Application\Service\FileManager();
//...
echo $f->file('file', 'test', 'pls choose');
Then I submit my form back to the controller. There (BTW all other form fields arrive in the controller as expected) I do:
$files = $this->post('test');
$file = \File::getByID($files);
which should return a File object. When I do
$file = \File::getRelativePathFromID($files);
it gives me the correct path to the chosen file.
So far so good. BUT when I try to send a mail with exactly that file object attached:
$mail = Loader::helper('mail');
$mail->setTesting(false);
$mail->setSubject('test-subject');
$mail->to($this->post('uEmail'));
//...
$attach = $mail->addAttachment($file);
$attach->filename = 'tttt';
$mail->sendMail();
the following error occurs:
call_user_func_array() expects parameter 1 to be a valid callback,
class 'Concrete\Core\File\Version' does not have a method 'getPath'
which apparently comes from this class method (API):
namespace Concrete\Core\Mail;
//...
class Service {
//...
/**
* Add attachment to send with an email.
*
* Sample Code:
* $attachment = $mailHelper->addAttachment($fileObject);
* $attachment->filename = "CustomFilename";
* $mailHelper->send();
*
* #param File $fob File to attach
* #return StdClass Pointer to the attachment
*/
public function addAttachment(\Concrete\Core\File\File $fob)
{
// #TODO make this work with the File Storage Locations
$fv = $fob->getVersion();
$path = $fob->getPath();
$name = $fv->getFileName();
//...
}
//...
}
which apparently wants a file object as param, which I think I passed, weren't I?
Why my file object becomes a FileVersion object, which, as I see by myself, hasn't got a method getPath().
My other trials so far:
$fv = $f->getApprovedVersion();
$fv->setFile($f);
$fv->getFile();
$fv = $f->getRecentVersion();
$fv->setFile($f);
$fv->getFile();
How do I get the correct file object, which I have to, maybe (??) , take out of the last/approved Version of this file?
This was a bug that has been fixed in the upstream, you'll have to either patch this yourself or wait until version 7.4 lands.

Doctrine Tree path iteration in Symfony 2

I have variable $path which contains the array of the names of sibling categories. Using this variable I would like to create a new array $categories_children, that would contain the array of children of each category from $path array according to its title. I'm using Doctrine Tree-Nestedset extension by Gediminas Morkevicius and I've tried this:
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('MyProjectAdminBundle:Category');
$category = $repo->findOneById($id);
$path = $repo->getPath($category);
$categories_children = array();
foreach($path as $node){
$parent = $repo->findOneByTitle($node);
$categories_children[] = $repo->getChildren($parent, true);
}
The problem is that method getChildren() with argument $parent returns the same array as like when the passed argument is NULL. That means it will return all nodes starting with root, instead of starting with selected category. Somehow method findOneByTitle(), which is being used in $parent variable, doesn't accept arguments from getPath() and behaves as NULL.
getChildren $parent argument specify only from which root element get the tree. You can see code of childrenQueryBuilder function in NestedTreeRepository.
To fetch all childs I use own function in repository.
public function getTreeAsFlatArray( AbstractTreeNode $parent = null, array $options = array() ) {
$qb = $this->createQueryBuilder('node');
$qb
->andWhere('node.lft > :parent_lft')
->setParameter('parent_lft', $parent->getLft() )
->andWhere('node.lft < :parent_rgt')
->setParameter('parent_rgt', $parent->getRgt() )
->andWhere('node.level <= :level')
->setParameter('level', $parent->getLevel() + $o['depth'])
->andWhere('node.root = :root')
->setParameter('root', $parent->getRoot())
;
...
}
If you only need direct childs simplets way to specify childs field in entity
/**
* #ORM\OneToMany(targetEntity="AbstractTreeNode", mappedBy="parent", fetch="EXTRA_LAZY")
* #ORM\OrderBy({"lft" = "ASC"})
*/
protected $childs;

Resources