I am trying to save the image using faker in the storage folder. I want to keep the images inside the property ID folder. I have tried the below code but it is not working. It hangs the command prompt. The properties have multiple images and are a one-to-many relation. The code below is for the PropertyImageFactory class.
public function definition()
{
$property_id = $this->create(Property::class)->id;
return [
'name' => $this->faker->image(storage_path('app/property-images/'.$property_id), 200, 200, 'cats'),
'sort_order' => $this->faker->numberBetween(1, 10),
'created_at' => now(),
'updated_at' => now(),
];
}
Laravel documentation has 'user_id' => User::factory(), I can't use this because it returns an object and I can't concatenate to string.
Below is the code for the property seeder.
public function run()
{
Property::factory()
->has(Category::factory()->count(3))
->has(PropertyImage::factory()->count(3), 'images')
->count(5)
->create();
}
Laravel documentation has 'user_id' => User::factory(), I can't use this because it returns an object and I can't concatenate to string.
Yup, that will return a UserFactory object just as Property::factory() will return a PropertyFactory. What you want to do is call the create() method on the factory and get the id from the record that is created.
$proprty_id = (\App\Models\Property::factory()->create())->id;
Laravel extracts the ID from the SomeModel::factory(), that's all the magic of Laravel. To do this, you need to properly describe the SomeModelFatory. You can use: $property_id = Property::factory();
As far as I know faker->image no longer works, I can advise using an auxiliary class for image formation.
<?php
namespace App\Helpers;
use Faker\Factory;
use Illuminate\Support\Facades\File;
class Image
{
public static function imageUrl(
int $width = 640,
int $height = 480,
bool $randomizeColors = false,
bool $randomizeTxt = false,
string $format = 'jpg'
): string
{
$baseUrl = "https://dummyimage.com";
$size = "/{$width}x{$height}";
$colors = "/aaa/fff";
$format = '.' . preg_replace('~^\b(?:jpg|png|gif)$~', 'jpg', $format);
if ($randomizeColors) {
$backgroundColor = str_replace('#', '', Factory::create()->safeHexColor);
$foreColor = str_replace('#', '', Factory::create()->safeHexColor);
$colors = "/{$backgroundColor}/{$foreColor}";
}
return $baseUrl . $size . $colors . $format . ($randomizeTxt ? '&text=' . Factory::create()->word : '');
}
public static function fake(
string $dir = null,
int $width = 640,
int $height = 480,
bool $randomizeColors = false,
bool $randomizeTxt = false,
string $format = 'jpg',
bool $fullPath = false
)
{
$dir = is_null($dir) ? sys_get_temp_dir() : $dir;
if (!is_dir($dir) || !is_writable($dir)) {
throw new \InvalidArgumentException("Unable to write to directory $dir");
}
$name = md5(uniqid(empty($_SERVER['SERVER_ADDR']) ? '' : $_SERVER['SERVER_ADDR'], true));
$filename = $name . ".$format";
$filepath = $dir . DIRECTORY_SEPARATOR . $filename;
$url = static::imageUrl($width, $height, $randomizeColors, $randomizeTxt, $format);
try {
$image = file_get_contents($url, false, stream_context_create(['http' => ['timeout' => 10]]));
try {
if (!File::put($filepath, $image)) {
return false;
}
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
return $fullPath ? $filepath : $filename;
}
}
and use:
public function definition()
{
$property_id = Property::factory();
$dir = storage_path('app' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . $property_id);
mkdir($dir, 755);
return [
'name' => (\App\Helpers\Image())->fake($dir, 200, 200),
'sort_order' => $this->faker->numberBetween(1, 10)
];
}
Related
It is not possible to transfer data from one controller to another. There is such a controller for filling mp3 files via Dropzone.JS:
public function upload(Request $request)
{
if (!$request->has('file')) {
return response()->json(['message' => 'Missing file'], 422);
}
$file = $request->file('file');
$extension = !is_null($file->extension()) ? $file->extension() : 'mp3';
$fileName = !is_null($file->getClientOriginalName()) ? rtrim($file->getClientOriginalName(), '.') : 'Unknown - Unknown.mp3';
$tracksPath = 'public/tracks/';
$globalPath = storage_path('app/public/tracks/');
$globalTrackPath = $globalPath . $fileName;
$file->move(storage_path('app/public/tracks'), $fileName);
$fileHash = sha1_file($globalTrackPath);
rename($globalTrackPath, $globalPath . $fileHash . '.' . $extension);
$track = GetId3::fromDiskAndPath('storage', 'app/public/tracks/' . $fileHash . '.' . $extension);
$t = $track->extractInfo();
$title = !empty($t['tags']['id3v2']['title']['0']) ? $t['tags']['id3v2']['title']['0'] : 'Unknown';
$artist = !empty($t['tags']['id3v2']['artist']['0']) ? $t['tags']['id3v2']['artist']['0'] : 'Unknown';
$band = !empty($t['tags']['id3v2']['band']['0']) ? $t['tags']['id3v2']['band']['0'] : '';
$album = !empty($t['tags']['id3v2']['album']['0']) ? $t['tags']['id3v2']['album']['0'] : '';
$year = !empty($t['tags']['id3v2']['year']['0']) ? $t['tags']['id3v2']['year']['0'] : '';
$genre = !empty($t['tags']['id3v2']['genre']['0']) ? $t['tags']['id3v2']['genre']['0'] : '';
$url = Storage::url($tracksPath . $fileHash . '.mp3');
if(!empty($track->getArtwork(true))) {
$tmpCoverFile = $track->getArtwork(true)->getPathname();
$coverPath = 'public/tracks/covers/';
$cover64Path = 'cover.jpg';
Storage::disk('local')->put($coverPath . '/' . $fileHash . '/' . $cover64Path, File::get($tmpCoverFile));
$cover = Storage::url($coverPath . $fileHash . '/' . $cover64Path);
} else {
$cover = '/vendor/songs-crud/images/none.png';
}
DB::table('songs_tracks')->updateOrInsert(
['hash' => $fileHash],
[
'release_id' => $request->id,
'image' => $cover,
'name' => $title,
'artist' => $artist,
'band' => $band,
'album' => $album,
'year' => $year,
'genre' => $genre,
'url' => $url,
'hash' => $fileHash,
'sortable' => '',
'slug' => $fileHash
]
);
$getTrackId = DB::table('songs_tracks')
->where('hash', $fileHash)
->first();
$id = !empty($getTrackId->id) ? $getTrackId->id : 1;
return $id;
}
The function works fine, media files are uploaded to the server and records are added to the database table. I need to pass the id to another function that generates a JSON file:
public function getTrackListJson(Request $request): \Illuminate\Http\JsonResponse
{
dd($this->upload());
$tracks = DB::table('songs_tracks')->where('id', $id)->first();
return response()->json([$tracks]);
}
I'm trying to print this function via dd(), but it gives the following error:
ArgumentCountError
Too few arguments to function SequelONE\SongsCRUD\app\Http\Controllers\Admin\TrackCrudController::upload(), 0 passed in /home/site.com/packages/sequelone/songs-crud/src/app/Http/Controllers/Admin/TrackCrudController.php on line 229 and exactly 1 expected
I can't figure out how to pass an instance of $request and do I need to pass it at all? Can anyone help with this?
When you call a function that requires parameter, or uses injection like the Laravel Request, then you need to pass it in when you call the function manually. Since you're already injecting Request $request on your getTrackListJson call, you can just pass that along.
dd($this->upload($request));
That might help
public function getTrackListJson(Request $request): \Illuminate\Http\JsonResponse
{
$id = $this->upload($request);
$tracks = DB::table('songs_tracks')->where('id', $id)->first();
return response()->json([$tracks]);
}
In my property section I have two property types:
Freemium
Premium
I want to restrict users to upload only 5 images for Freemium property type while for Premium properties a user can upload infinitive number images and videos.
Must needed some suggestions.
Here is my image upload part :
public function postProperty(PropertyRequest $request)
{
$user = User::where('id', $request->user->user_id)->first();
if(!empty($user))
{
$data['user_id'] = $user->id;
$data['type'] = $request->type;
$data['category'] = $request->category;
$data['area'] = $request->area;
$data['price'] = $request->price;
$data['description'] = $request->description;
//dd($data);
$property = Property::create($data);
//$property['flag'] = false; // if (flag = false, property = freemium) else (flag = true, property = premium ))
$urls = new PropertyImage();
if ($request->hasFile('url'))
{
$files = $request->file('url');
foreach($files as $file)
{
$mime = $file->getMimeType();
//$property['flag'] = $property->account == 1 ? false : true;
if($mime == 'image/jpeg')
{
$fileName = $file->getClientOriginalName();
$destinationPath = public_path() . '/images/';
$file->move($destinationPath, $fileName);
$urls->url = '/public/images/' . $fileName;
$url_data = [
'property_id' => $property->id,
'url_type' => 1,
'url' => $urls->url,
];
$urls->create($url_data);
}
elseif($mime == 'video/mp4')
{
$fileName = $file->getClientOriginalName();
$destinationPath = public_path() . '/videos/';
$file->move($destinationPath, $fileName);
$urls->url = '/public/videos/' . $fileName;
$url_data = [
'property_id' => $property->id,
'url_type' => 2,
'url' => $urls->url,
];
$urls->create($url_data);
}
}
}
return Utility::renderJson(trans('api.success'), true, $property, $urls );
}
}
You can use laravel validation to restrict user to some number of files as shown below
//If user is Freemium then restrict him
if (!$property['flag']) {
$messages = [
"url.max" => "files can't be more than 3."
];
$this->validate($request, [
'url' => 'max:3',
],$messages);
}
I have a question about Abstract Validators. I was trying to implement the solution of Mb Rostami found here.
This is the error I get:
Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for Application\Validators\File\Image
All I need to do I guess is to somehow inject the class into the model. What is Application\Validators\File\Image?
So how to fix this error? Most easy solution would be to add the validator class as an invocable to the module?
The input filter in model class:
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'eid',
'required' => true,
'filters' => array(
array('name' => 'Int'),
)
));
$newFileName = sha1(time(), true);
$inputFilter->add(
array(
'name' => 'ImageValidator',
'required' => true,
'validators' => array(
array(
'name' => '\Application\Validators\File\Image',
'options' => array(
'minSize' => '64',
'maxSize' => '5120',
'newFileName' => $newFileName,
'uploadPath' => './data/'
),
),
)
)
);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
Validator class:
<?php
namespace Application\Validators\File;
use Zend\Validator\File\Extension;
use Zend\File\Transfer\Adapter\Http;
use Zend\Validator\File\FilesSize;
use Zend\Filter\File\Rename;
use Zend\Validator\File\MimeType;
use Zend\Validator\AbstractValidator;
class Image extends AbstractValidator
{
const FILE_EXTENSION_ERROR = 'invalidFileExtention';
const FILE_NAME_ERROR = 'invalidFileName';
const FILE_INVALID = 'invalidFile';
const FALSE_EXTENSION = 'fileExtensionFalse';
const NOT_FOUND = 'fileExtensionNotFound';
const TOO_BIG = 'fileFilesSizeTooBig';
const TOO_SMALL = 'fileFilesSizeTooSmall';
const NOT_READABLE = 'fileFilesSizeNotReadable';
public $minSize = 64; //KB
public $maxSize = 1024; //KB
public $overwrite = true;
public $newFileName = null;
public $uploadPath = './data/';
public $extensions = array('jpg', 'png', 'gif', 'jpeg');
public $mimeTypes = array(
'image/gif',
'image/jpg',
'image/png',
);
protected $messageTemplates = array(
self::FILE_EXTENSION_ERROR => "File extension is not correct",
self::FILE_NAME_ERROR => "File name is not correct",
self::FILE_INVALID => "File is not valid",
self::FALSE_EXTENSION => "File has an incorrect extension",
self::NOT_FOUND => "File is not readable or does not exist",
self::TOO_BIG => "All files in sum should have a maximum size of '%max%' but '%size%' were detected",
self::TOO_SMALL => "All files in sum should have a minimum size of '%min%' but '%size%' were detected",
self::NOT_READABLE => "One or more files can not be read",
);
protected $fileAdapter;
protected $validators;
protected $filters;
public function __construct($options)
{
$this->fileAdapter = new Http();
parent::__construct($options);
}
public function isValid($fileInput)
{
$options = $this->getOptions();
$extensions = $this->extensions;
$minSize = $this->minSize;
$maxSize = $this->maxSize;
$newFileName = $this->newFileName;
$uploadPath = $this->uploadPath;
$overwrite = $this->overwrite;
if (array_key_exists('extensions', $options)) {
$extensions = $options['extensions'];
}
if (array_key_exists('minSize', $options)) {
$minSize = $options['minSize'];
}
if (array_key_exists('maxSize', $options)) {
$maxSize = $options['maxSize'];
}
if (array_key_exists('newFileName', $options)) {
$newFileName = $options['newFileName'];
}
if (array_key_exists('uploadPath', $options)) {
$uploadPath = $options['uploadPath'];
}
if (array_key_exists('overwrite', $options)) {
$overwrite = $options['overwrite'];
}
$fileName = $fileInput['name'];
$fileSizeOptions = null;
if ($minSize) {
$fileSizeOptions['min'] = $minSize * 1024;
}
if ($maxSize) {
$fileSizeOptions['max'] = $maxSize * 1024;
}
if ($fileSizeOptions) {
$this->validators[] = new FilesSize($fileSizeOptions);
}
$this->validators[] = new Extension(array('extension' => $extensions));
if (!preg_match('/^[a-z0-9-_]+[a-z0-9-_\.]+$/i', $fileName)) {
$this->error(self::FILE_NAME_ERROR);
return false;
}
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
if (!in_array($extension, $extensions)) {
$this->error(self::FILE_EXTENSION_ERROR);
return false;
}
if ($newFileName) {
$destination = $newFileName . ".$extension";
if (!preg_match('/^[a-z0-9-_]+[a-z0-9-_\.]+$/i', $destination)) {
$this->error(self::FILE_NAME_ERROR);
return false;
}
} else {
$destination = $fileName;
}
$renameOptions['target'] = $uploadPath . $destination;
$renameOptions['overwrite'] = $overwrite;
$this->filters[] = new Rename($renameOptions);
$this->fileAdapter->setFilters($this->filters);
$this->fileAdapter->setValidators($this->validators);
if ($this->fileAdapter->isValid()) {
$this->fileAdapter->receive();
return true;
} else {
$messages = $this->fileAdapter->getMessages();
if ($messages) {
$this->setMessages($messages);
foreach ($messages as $key => $value) {
$this->error($key);
}
} else {
$this->error(self::FILE_INVALID);
}
return false;
}
}
}
The solution was simple, at least in my case. Like I mentioned above: check the folder structure. Zend Framework has it's own way of structuring project files, so the file path needs to match.
I am currently doing an internship and I tried to make an activity module to show playlist, from video given by a filemanager. I succeed to send the video to the database but when I want to edit my module, it doesn't show any videos in the filemanager.
I read the moodle documentation about file API and I decided to use the following code (Load existing files into draft area)
:
if (empty($entry->id)) {
$entry = new stdClass;
$entry->id = null;
}
$draftitemid = file_get_submitted_draft_itemid('attachments');
file_prepare_draft_area($draftitemid, $context->id, 'mod_glossary','attachment', $entry->id,array('subdirs' => 0, 'maxbytes' => $maxbytes, 'maxfiles' => 50));
$entry->attachments = $draftitemid;
$mform->set_data($entry);
So I put the following lines in my mod_form.php :
$filemanager_options = array();
$filemanager_options['accepted_types'] = '*';
$filemanager_options['maxbytes'] = 0;
$filemanager_options['maxfiles'] = -1;
$filemanager_options['mainfile'] = true;
$mform->addElement('filemanager', 'files', get_string('selectfiles'), null, $filemanager_options);
if (empty($entry->id)) {
$entry = new stdClass;
$entry->id = null;
}
$draftitemid = file_get_submitted_draft_itemid('mymanager');
file_prepare_draft_area($draftitemid, $this->context->id, 'mod_playlist', 'content', 0,
array('subdirs'=>true));
$entry->attachments = $draftitemid;
$mform->set_data($entry);
The problem is that the file manager is still empty, and the line "$mform->set_data($entry); " makes the page to crash(blank).
Here is a template for uploading files.
In local/myplugin/upload.php
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
require_once(dirname(__FILE__) . '/upload_form.php');
require_login();
$context = context_system::instance();
require_capability('local/myplugin:upload', $context);
$pageurl = new moodle_url('/local/myplugin/upload.php');
$heading = get_string('myupload', 'local_myplugin');
$PAGE->set_context($context);
$PAGE->set_heading(format_string($heading));
$PAGE->set_title(format_string($heading));
$PAGE->set_url('/local/myplugin/upload.php');
echo $OUTPUT->header();
echo $OUTPUT->heading($heading);
$fileoptions = array(
'maxbytes' => 0,
'maxfiles' => '1',
'subdirs' => 0,
'context' => context_system::instance()
);
$data = new stdClass();
$data = file_prepare_standard_filemanager($data, 'myfiles',
$fileoptions, context_system::instance(), 'local_myplugin', 'myfiles', 0); // 0 is the item id.
$mform = new upload_form(
null,
array(
'fileoptions' => $fileoptions,
)
);
if ($formdata = $mform->get_data()) {
// Save the file.
$data = file_postupdate_standard_filemanager($data, 'myfiles',
$fileoptions, context_system::instance(), 'local_myplugin', 'myfiles', 0);
} else {
// Display the form.
$mform->set_data($data);
$mform->display();
}
echo $OUTPUT->footer();
Then in local/myplugin/upload_form.php
defined('MOODLE_INTERNAL') || die;
require_once($CFG->libdir . '/formslib.php');
class upload_form extends moodleform {
public function definition() {
$mform =& $this->_form;
$fileoptions = $this->_customdata['fileoptions'];
$mform->addElement('filemanager', 'myfiles_filemanager',
get_string('myfiles', 'local_myplugin'), null, $fileoptions);
$this->add_action_buttons(false, get_string('save', 'local_myplugin'));
}
}
You will also need this in /local/myplugin/lib.php
function local_myplugin_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) {
if ($context->contextlevel != CONTEXT_SYSTEM) {
send_file_not_found();
}
$fs = get_file_storage();
$file = $fs->get_file($context->id, 'local_myplugin', $filearea, $args[0], '/', $args[1]);
send_stored_file($file);
}
I have a class that takes photos I download before reuploading to S3 for long-term storage and I want to trim the white space. When I store the temporary image (which works fine), I then try to call the Intervention trim() on it in my storeTempFile() method but that doesn't trim the white space. I'm thinking it could be the placement in my code?
class PhotoProcessor
{
public function __construct(Listing $listing, $photoData)
{
$this->bucket = 'real-estate-listings';
$this->s3 = App::make('aws')->get('s3');
$this->tempFileName = 'app/storage/processing/images/retsphotoupload';
$this->photoData = $photoData;
$this->listing = $listing;
$this->photo = new RetsPhoto;
}
public function process()
{
$this->storeTempFile();
$this->storeFileInfo();
$this->buildPhoto();
$success = $this->pushToS3();
// if Result has the full URL or you want to build it, add it to $this->photo
DB::connection()->disableQueryLog();
$this->listing->photos()->save($this->photo);
$this->removeTempFile();
unset ($this->photoData);
return $success;
}
private function storeTempFile()
{
// return File::put($this->tempFileName, $this->photoData['Data']) > 0;
File::put($this->tempFileName, $this->photoData['Data']);
Image::make($this->tempFileName)->trim('top-left', null, 60);
return($this->tempFileName) > 0;
}
private function storeFileInfo()
{
$fileInfo = getimagesize($this->tempFileName);
// Could even be its own object
$this->fileInfo = [
'width' => $fileInfo[0],
'height' => $fileInfo[1],
'mimetype' => $fileInfo['mime'],
'extension' => $this->getFileExtension($fileInfo['mime'])
];
}
private function buildPhoto()
{
$this->photo->number = $this->photoData['Object-ID']; // Storing this because it is relevant order wise
$this->photo->width = $this->fileInfo['width'];
$this->photo->height = $this->fileInfo['height'];
$this->photo->path = $this->getFilePath();
}
private function getFilePath()
{
$path = [];
if ($this->listing->City == NULL)
{
$path[] = Str::slug('No City');
}
else
{
$path[] = Str::slug($this->listing->City, $separator = '-');
}
if ($this->listing->Subdivision->subdivision_display_name == NULL)
{
$path[] = Str::slug('No Subdivision');
}
else
{
$path[] = Str::slug($this->listing->Subdivision->subdivision_display_name, $separator = '-');
}
if ($this->listing->MLSNumber == NULL)
{
$path[] = Str::slug('No MLSNumber');
}
else
{
$path[] = Str::slug($this->listing->MLSNumber, $separator = '-');
}
$path[] = $this->photoData['Object-ID'].'.'.$this->fileInfo['extension'];
return strtolower(join('/', $path));
}
private function pushToS3()
{
return $this->s3->putObject([
'Bucket' => $this->bucket,
'Key' => $this->photo->path,
'ContentType'=> $this->fileInfo['mimetype'],
'SourceFile' => $this->tempFileName
]);
}
private function getFileExtension($mime)
{
// Use better algorithm than this
$ext = str_replace('image/', '', $mime);
return $ext == 'jpeg' ? 'jpg' : $ext;
}
private function removeTempFile()
{
return File::delete($this->tempFileName);
}
}
trim() returns the trimmed image, but you are doing nothing with the return value. Try calling save() to persist the image to the filesystem:
Image::make($this->tempFileName)->trim('top-left', null, 60)->save();
// ^^^^^^