Skip to content

Commit

Permalink
Refactor media storage and retrieval methods
Browse files Browse the repository at this point in the history
  • Loading branch information
rachyharkov committed Dec 4, 2023
1 parent 8600326 commit e7ebf7d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 136 deletions.
138 changes: 18 additions & 120 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ Codeigniter package for to handle media upload file task (at least help a bit fo

# Installation

## Composer

`composer require rachyharkov/codeigniter4-media`

## Setup Model
just set your model like this

```php
Expand Down Expand Up @@ -42,7 +45,7 @@ only use usingFileName method after addMediaFromRequest method, this will be use
$this->user_model->addMediaFromRequest('photo')->usingFileName('data_'.random(20))->toMediaCollection('profile_photo');
```

## Store Multi File
## Store Multi File - Different Name

store file from multi different request name (for example, you have 2 input file with different input file name attribute value, and you want to store it to same collection)

Expand All @@ -54,6 +57,19 @@ store file from multi different request name (for example, you have 2 input file
])
```

## Store Multi File - Same Name

This time using addMedia, make sure it's an file object (binary payload) to make addMedia accept value, in this example using multiple file input with same name attribute value

```php
$this->product_model->insert($data);
$product_images = $this->request->getFiles();

foreach ($product_images['photos'] as $key => $p) {
$this->product_model->addMedia($p)->toMediaCollection('product_image');
}
```

### Get Single File - Metadata

```php
Expand All @@ -74,6 +90,7 @@ above will return null if no file meta information returned, handle it like this
### Get Single File - Just URL

This is the example of how to assign new object to existing object (for example user object) with new property (photo) that contains the url of file

```php

$this->data['user']->photo = $this->user_model->mediaOf($this->data['user']->id,'profile_photo')->getFirstMediaUrl();
Expand Down Expand Up @@ -153,125 +170,6 @@ You will get this response
}
```

🪄 **Frontend Implementation**

it's easy to using alpineJS, but most of you are JQuery user, soo here it is..

Example using jquery

Set your html like this

```html

<div class="form-group">
<label for="file">File</label>
<input type="file" class="form-control" id="file" name="file">
</div>

<ul id="list_file"></ul>
```

Write your javascript like this

```js

let array_uploaded_file = [];

function render_list_file() {
let html = '';
array_uploaded_file.forEach((item, index) => {
html += `
<li style="font-size: 10px;">
<span>${item.name}</span>
<button type="button" class="btn btn-sm btn-copy-link" data-id="${index}"><i class="fa fa-copy"></i></button>
<button type="button" class="btn btn-sm btn-danger btn-delete-file" data-id="${index}"><i class="fa fa-trash"></i></button>
</li>`;
});
$('#list_file').html(html);
}

function copy_link(index) {
let url = array_uploaded_file[index].url;
navigator.clipboard.writeText(url).then(function() {
Toast.fire({
icon: 'success',
title: 'Success',
timer: 4000,
text: 'Link Copied Successfuly'
})
}, function() {
alert('Failed to copy link');
});
}

function upload_file(file, type) {

formData.append('file', file);

$.ajax({
url: '<?= url_to('admin.users.api_upload') ?>',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(resp) {
if(resp.status == 'success') {
array_uploaded_file.push({
name: resp.data.file_name,
url: '<?= base_url() ?>' + resp.data.file_path + '/' + resp.data.file_name,
temp_id: resp.data.unique_name
});
render_list_file();
}
}
});
}

function delete_file(index) {
$.ajax({
url: '<?= url_to('admin.users.api_delete') ?>',
type: 'POST',
data: {
temp_id: array_uploaded_file[index].temp_id
},
success: function(resp) {
if(resp.status == 'success') {
array_uploaded_file.splice(index, 1);
render_list_file();
Toast.fire({
icon: 'success',
title: 'Success',
timer: 4000,
text: resp.message
})
}
},
error: function() {
alert('Failed to delete file');
}
});
}

$('#file').on('change', function() {
let file = $(this).prop('files')[0];
upload_file(file, 'gambar');
});

$(document).on('click', '.btn-copy-link', function() {
copy_link($(this).data('id'));

$(this).html('<i class="fa fa-check text-success"></i>');
setTimeout(() => {
$(this).html('<i class="fa fa-copy"></i>');
}, 2000);
});

$(document).on('click', '.btn-delete-file', function() {
delete_file($(this).data('id'));
});

```

## Notes

Sorry if it looks completely messed up, i'm still develop an approach and functionality that might work like spatie media laravel.
Expand Down
8 changes: 8 additions & 0 deletions src/HasMedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ public function media(): Model;
*/
public function addMediaFromRequest($field): self;

/**
* add media
* @param $file
* @throws ValidationException
*/
public function addMedia($file): self;


/**
* Get all specified input files from request and validate it
* @param $array
Expand Down
36 changes: 20 additions & 16 deletions src/InteractsWithMedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function mediaOf(string $collectionName = 'default', string $id = null)
$this->model_id = $id;
$this->collectionName = $collectionName;

$this->media_builder = $this->media()->where('collection_name', $this->collectionName);
$this->media_builder = $this->media()->where('collection_name', $this->collectionName)->orderBy('id', 'DESC');

if ($this->model_id) {
$this->media_builder->where('model_id', $this->model_id);
Expand All @@ -61,7 +61,13 @@ public function mediaOf(string $collectionName = 'default', string $id = null)

public function getAllMedia()
{
return $this->media_builder->findAll();
$result = $this->media_builder->findAll();

foreach ($result as $key => $value) {
$result[$key]->file_url = base_url($value->file_path .'/'. $value->file_name.'.'.$value->file_ext);
}

return $result;
}

/**
Expand Down Expand Up @@ -91,8 +97,14 @@ public function addMediaWithRequestCollectionMapping(array $array): self
return $this;
}

public function addMedia($file): self
{
$this->validateFile($file);
$this->media_file = $file;
return $this;
}

/**
/**
* clear temp media, need unique name of who owns it, you can get it from putItInCollection() method before, you may specify it as api request or not by passing true or false to see the response
* @param string|null $id
*/
Expand Down Expand Up @@ -150,24 +162,16 @@ public function toMediaCollection(string $collectionName = 'default')


$this->setDefaultPath();

// used to store after insert data operation

try {
//https://forum.codeigniter.com/showthread.php?tid=78276&pid=382975#pid382975
$this->model_id = $this->getInsertID();
// how do we know model_id is not null? because clearMediaCollection() method will set model_id, it's dumb to not set model_id on clearMediaCollection() right?
$this->model_id = $this->getInsertID() == 0 ? $this->model_id : $this->getInsertID();
$this->temp_media_data['model_id'] = $this->model_id;
$this->storeMedia();

return $this;
} catch (\Throwable $th) {
if($this->model_id) { // if model id is not null, then it means that the model is already inserted, so we can continue to store the media
$this->temp_media_data['model_id'] = $this->model_id;

$this->storeMedia();

return $this;
}
// if model id is null, then it means the media not data-related, so we store it on collection
$this->putItInCollection();

return $this;
Expand Down Expand Up @@ -346,7 +350,7 @@ public function clearMediaCollection(string $collectionName = 'default', string
$pathinfo = pathinfo(ROOTPATH .'public/'. $v->file_path . $v->file_name);

if (is_dir($pathinfo['dirname'])) {
shell_exec('rm -rf ' . escapeshellarg($pathinfo['dirname'] . '/' . $v->model_id));
shell_exec('rm -rf ' . escapeshellarg($pathinfo['dirname'] . '/' . $v->id));
}
$this->media()->delete($v->id);
}
Expand Down

0 comments on commit e7ebf7d

Please sign in to comment.