I am trying to build a Youtube based application with Laravel 5.3. Using a library I am able to successfully retrieve the data from a playlist and display it. It is formatted like this:
[
{
0: {
kind: "youtube#playlistItem",
etag: ""I_8x5t5r66_FSaexwefRREftGc0/BO3zvggHrzgTTh_ZhXr745ww"",
id: "UExDQXc3VFJvaVBIX2VuXzMtcThnWW9ZZUc4YlVmX2dOUC4wMTcyMDhGQUE4NTIzM0Y5",
snippet: {
publishedAt: "2014-10-06T15:50:12.000Z",
channelId: "UCGT2vvwtBJ-0edGHEj5Tv67Q",
title: "S'More - La ricetta dei biscotti",
description: "Sul blog la storia, la ricetta e le foto",
thumbnails: {
default: {
url: "https://i.ytimg.com/vi/Hug-iFvDS3s/default.jpg",
width: "120",
height: "90"
},
medium: {
url: "https://i.ytimg.com/vi/Hug-iFvDS3s/mqdefault.jpg",
width: "320",
height: "180"
},
high: {
url: "https://i.ytimg.com/vi/Hug-iFvDS3s/hqdefault.jpg",
width: "480",
height: "360"
},
standard: {
url: "https://i.ytimg.com/vi/Hug-iFvDS3s/sddefault.jpg",
width: "640",
height: "480"
},
maxres: {
url: "https://i.ytimg.com/vi/Hug-iFvDS3s/maxresdefault.jpg",
width: "1280",
height: "720"
}
},
channelTitle: "Ricette di Famiglia",
playlistId: "PLCAB2ddt6H_en_3-q8gRfTYsbUf_gNP",
position: "0",
resourceId: {
kind: "youtube#video",
videoId: "Hug-iFvDS3s"
}
}
},
...
]
My next step would be grabbing the array containing video related data, conveniently map each item to a Video class instance and finally store each video item into my database. Does anyone have any idea how can I acheive that?
You can accomplish the this by using the following. From the API response you have provided in your question, there is an array of objects, and those objects have objects inside them, so you will need two loops.
// $json is the JSON response you get from the API
$entities = json_decode($json);
foreach ($entities as $entity) {
$items = get_object_vars($entity);
// Each $item is a video object from the API response
foreach ($items as $item) {
// Create a new Video object and persist it in the DB
$video = new Video();
$video->create([
'kind' => $item->kind,
'published_at' => $item->publishedAt,
...
]);
}
}
Related
I have an update ( patch form ) that can have some basic fields with one featured image and an array of gallery images.
updatePhotoPreview(event) {
this.featuredImagePreview = URL.createObjectURL(event.target.files[0])
this.updateProductForm.featured_image = event.target.files[0]
},
Before sending the request and even in the request header, the featured image is File and binary.
Then I'm simply posting the form with this.form.patch(url).
I'm getting an error the featured_image must be an image.
I've dumped the request and somehow my featured_image value has been set to an empty array.
The same is for the gallery images, it has been turned into an array of empty arrays.
I've tried changing the route to post, put, the result is the same, I've added a custom header
{ headers: {'Content-Type': 'multipart/form-data'} }
The result is the same.
but the same form is working for the create endpoint of this resource with POST method.
I've removed all the request classes and dumping with request()->all()
How can I fix this?
It's possible to upload a photo via InertiaJS and Laravel 8 following the steps below:
In our VueJS component's HTML:
<input type="file" class="hidden"
ref="photo"
#change="updatePreview">
<div v-show="preview">
<span class="block w-20 h-20 rounded-full"
:style="'width: 5rem; height: 5rem; border-radius: 999px; display: block; background-size: cover; background-repeat: no-repeat; background-position: center center; background-image: url(\'' + photoPreview + '\');'">
</span>
</div>
In our methods object:
updatePhotoPreview() {
const reader = new FileReader();
reader.onload = (e) => {
this.preview = e.target.result;
};
reader.readAsDataURL(this.$refs.photo.files[0]);
},
storePhoto() {
if (this.$refs.photo) {
this.form.photo = this.$refs.photo.files[0]
}
this.form.post(route('photo.store'), {
preserveScroll: true
});
},
In our data function:
data() {
return {
form: this.$inertia.form({
'_method': 'PUT',
photo: null,
}, {
resetOnSuccess: false,
}),
preview: null,
}
},
In our Laravel Controller:
class PhotoController
{
public function store(array $input)
{
Validator::make($input, [
'photo' => ['nullable', 'image', 'max:1024'],
]);
if (isset($input['photo'])) {
$photo->storePublicly();
}
}
}
I fix this by adding '_method' on form and using 'post' request.
data() {
return {
form: this.$inertia.form({
_method: "PUT",
})
};
},
methods: {
submit(form) {
this.form
.post("route/id", form, {
preserveState: true
})
}
}
var data = new FormData()
data.append('first_name', first_name || '')
data.append('last_name', last_name || '')
data.append('email', email || '')
data.append('password', password || '')
data.append('photo', photo || '')
Inertia.post('/users', data)
Try this. Just use FormData() instantiation
Please refer the documentation https://inertiajs.com/forms#file-uploads
use formData
const fd = new FormData()
fd.append('file', this.form.file)
this.$inertia.post(route('file.register'), fd)
Has anyone been able to use SendGrid templates with Parse Cloud Code?
This works, but only sends text, any ideas on how to use a template_id?
I tried with the filter but was not successful.
Parse.Cloud.define("sendEmail", function(request, response) {
// Import SendGrid module and call with your SendGrid API Key
var sg = require('sendgrid')('your SendGrid API key here');
// Create the SendGrid Request
var reqSG = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: {
personalizations: [
{
to: [
{
// This field is the "to" in the email
email: request.params.toEmail,
},
],
// This field is the "subject" in the email
subject: request.params.subject,
},
],
// This field contains the "from" information
from: {
email: 'info#youremail.com',
name: 'Your Name',
},
// This contains info about the "reply-to"
// Note that the "reply-to" may be different than the "from"
reply_to: {
email: 'info#youremail.com',
name: 'Your Name',
},
content: [
{
type: 'text/plain',
value: request.params.body,
},
],
},
});
sg.API(reqSG, function(SGerror, SGresponse) {
// Testing if some error occurred
if (SGerror) {
// Ops, something went wrong
console.error('Error response received');
console.error('StatusCode=' + SGresponse.statusCode);
console.error(JSON.stringify(SGresponse.body));
response.error('Error = ' + JSON.stringify(SGresponse.body));
}
else {
// Everything went fine
console.log('Email sent!');
response.success('Email sent!');
}
});
});
This is from the documentation on Back4App https://docs.back4app.com/docs/integrations/using-sendgrid-to-send-email/
If anyone is looking for the answer it turned out to be simple,
add the template_id as a personalization and change the message type the text/html,
template_id:"your template_id",
content: [
{
type: 'text/html',
// This field is the body of the email
value: "",
},
],
I am having an issue trying to use the addInitialFiles method listed here:
http://docs.fineuploader.com/branch/master/api/methods.html#addInitialFiles
I get a javascript error in my chrome dev console that says:
1032:381 Uncaught TypeError: uploader.addInitialFiles is not a function
This is the code I use to initialize Fine Uploader, and make the call the addInitialFiles():
<script type="text/javascript">
$(function () {
var uploader = $('#fine-uploader').fineUploaderS3({
request: {
endpoint: "myfineuploaderbucket.com.s3.amazonaws.com",
accessKey: "XXXXXXXXXXXXXXXXXXXXXXXX",
},
signature: {
endpoint: "/SignatureHandler",
version: 4
},
validation: {
allowedExtensions: ["gif", "jpeg", "jpg", "png", "bmp"],
acceptFiles: "image/gif, image/jpeg, image/png, image/bmp",
sizeLimit: 5000000,
itemLimit: 3
},
retry: {
enableAuto: true
},
deleteFile: {
enabled: true,
endpoint: "/DeleteImage/?id=#Model.Id",
method: 'POST',
},
paste: {
targetElement: $(document),
promptForName: true
},
uploadSuccess: {
endpoint: "/UploadSuccessful/?id=#Model.Id"
},
iframeSupport: { //This path needs to be a blank HTML page and is used for fine-uploader to support IE9 and older
localBlankPagePath: "/Blank"
},
objectProperties: {
acl: "public-read",
key: function (fileId) {
var re = /(?:\.([^.]+))?$/;
fileExt = re.exec($("#fine-uploader").fineUploader("getName", fileId))[0];
uuid = $("#fine-uploader").fineUploader("getUuid", fileId);
filename = uuid + fileExt;
key = "/#ViewBag.Id + "/" + filename;
return key;
}
},
scaling: {
hideScaled: true,
sizes: [
{ name: "small", maxSize: 350 },
{ name: "large", maxSize: 800 },
]
},
callbacks: {
onDelete: function (id) {
if (id == 2) {
$("#fine-uploader").fineUploader("deleteFile", 0);
$("#fine-uploader").fineUploader("deleteFile", 1);
}
},
},
});
uploader.addInitialFiles([
{
"name": "a3ef2360-881d-452c-a5f6-a173d5291066.jpg",
"uuid": "a3ef2360-881d-452c-a5f6-a173d5291066",
"size": "66000",
"thumbnailUrl": "https://s3.amazonaws.com/myfineuploaderbucket.com/1032/ecdca7bb-fb02-4072-b526-4e51cedb1f2b.jpg",
"s3Key": "1032/a3ef2360-881d-452c-a5f6-a173d5291066.jpg",
"s3Bucket": "myfineuploaderbucket.com"
}
]);
Is there something that I am doing wrong? Is addInitialFiles not a method, but an option that needs to be initialized when creating the Fine Uploader instance? I have tried adding "addInitialFiles" to the options of the Fine Uploader instance as well, and I do not receive a javascript error, but it does not load the initial file either.
I am using the latest version, 5.7.1.
Just like any other jQuery plug-in, the Fine Uploader jQuery wrapper returns a jQuery-wrapped element. This means that you are attempting to call an addInitialFiles method on a jQuery object. Of course, this method does not exist. If you really want to continue using the jQuery wrapper, you must change uploader.addInitialFiles(...) to uploader.fineUploaderS3('addInitialFiles', ...).
But you should know that you don't need jQuery for any of this, especially when using Fine Uploader. There is no benefit to using the jQuery wrapper with Fine Uploader, and you can fix your code simply by forgoing the wrapper (and saving a few bytes) and changing the first couple lines of your Fine Uploader initialization to:
var uploader = new qq.s3.FineUploader({
element: document.querySelector('#fine-uploader'),
...
})
Now, uploader.addInitialFiles works as you would expect.
I am new to Extjs4 and the javascript world in general. I have looked up the documentation and samples and trying to get a basic CRUD grid up and running with my spring backend.
I have a confusion related to the proxy in extjs, are they in the store or model according to the MVC paradigm ?
I have a controller.js defined which wraps these up together.
I would have thought that the REST calls would be made accroding to the urls being specified, which it is for now , but a create call is still sending the entire list. I am using jackson at the backend for automatic conversion to java objects but somehow that is not working (for add and update only).
How do i link these all up ?
a) Add a user .. do i create a new UserModel and then invoke a rest call like so or is it automatically supported by the proxy specified in the model ?
var record = new App.model.UserModel();
store = Ext.getStore('UsersStore');
store.insert(0, record);
store.save(); // .. this invokes the /createUser method
// .. what about /update ?
b) I am using the RowEditing plugin .. how can i fetch the roweditor in my controller.js where the reference for the view is available
Thanks in advance
relevant code listings ...
//UserController.js
Ext.define('App.controller.UsersController', {
extend : 'Ext.app.Controller',
init: function() {
this.control({
'userList button[action=add]' : {
click : this.editUser
} }); },
views : ['user.List','user.Edit'],
stores : ['UsersStore'] ,
models : ['UserModel'],
editUser : function(grid,record)
{
// empty record
var record = new App.model.UserModel();
// created new record
//How to get a reference to the roweditor here and then save that to the backend ?
//store = Ext.getStore('UsersStore');
//store.insert(0, record);
//store.save();
// this.getView('user.List').getP('rowEditor').startEdit(0, 0);
}});
//List.js
var rowEditor = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToEdit: 2
}
Ext.define('App.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userList',
title : 'All Users',
store : 'UsersStore',
selType: 'rowmodel',
plugins: rowEditor,
initComponent: function() {
this.columns = [
{header: 'SNo', dataIndex: 'userID', width:50},
{header: 'UID', dataIndex: 'userUID', flex: 1, editor: 'textfield', allowBlank:false},
{header: 'Name', dataIndex: 'userName', flex: 1, editor:'textfield',allowBlank:false},
{ header: 'Level', dataIndex: 'userLevel', flex: 1,
editor: {xtype: 'combobox', typeAhead: true, triggerAction: 'all', selectionOnTab:true,
store : [
['Level 1','Level 1'],
['Level 2','Level 2'],
['Level 3','Level 3']
]
}
},
{header: 'Email', dataIndex: 'emailID', flex: 1, editor: 'textfield'}
];
this.callParent(arguments);
},
dockedItems : [{
xtype : 'toolbar',
items : [{
text: 'Add',
iconCls: 'icon-add',
action: 'add'
}]
}]});
//Model.js
Ext.define('App.model.UserModel', {
extend: 'Ext.data.Model',
fields: ['userID','userUID','userName', 'userLevel' ,'emailID'],
proxy : {
type: 'ajax',
api :
{
read : 'rest/user/fetchAll',
update:'rest/user/updateUser',
create :'rest/user/createUser',
destroy : 'rest/user/deleteUser'
},
reader :
{
type : 'json',
root : 'users',
successProperty : 'success'
},
writer :
{
type : 'json',
allowSingle : 'true'
}
}});
//UserStore
Ext.define('App.store.UsersStore', {
extend: 'Ext.data.Store',
model: 'App.model.UserModel',
autoLoad : true});
//Sample Java controller
#Controller
#RequestMapping("/rest/user")
public class UserController {
#RequestMapping(value = "/fetchAll" , method= RequestMethod.GET)
public #ResponseBody Map<String,? extends Object>
fetchUsers() {
Map<String,Object> responseMap = new HashMap<String,Object>();
responseMap.put("success",true);
responseMap.put("users",userService.getUserRepository().findAll());
return responseMap; }
// was expecting a single object here ?
#RequestMapping(value = "/createUser")
public #ResponseBody Map<String,? extends Object>
createUser(#RequestBody List<User> users)
{ ... }
}
I would put Proxy's inside store objects, not models. But that just personal preference.
When you add record to the store object, if it has autoSync property set to true it would automatically generate create request. What exactly is happening with your create request? What is being sent?
After trying out Sha's comments above, i was finally able to nail the issue.
The problem is with the json reader
reader :
{
type : 'json',
root : 'users',
successProperty : 'success'
//added
idProperty : 'userID'
},
I had to add the idProperty to make Json recognize the dirty record, else it treats everything as a new record and sends back the whole list
Developing a Sencha Touch MVC app that pulls data from json store (thats set up to a DB pulling out content from a Wordpress Blog).
Everything works up until my "detail" panel. Instead of it listening to the TPL, its just dumping some data. The data looks similar to my blog post, but is filled with other code and doesn't make much sense.
Here is a lean version of my list:
myApp.views.PostListView = Ext.extend(Ext.Panel, {
postStore: Ext.emptyFn,
postList: Ext.emptyFn,
id:'postlistview',
layout: 'card',
initComponent: function () {
/* this.newButton = new Ext.Button({
text: 'New',
ui: 'action',
handler: this.onNewNote,
scope: this
});*/
this.topToolbar = new Ext.Toolbar({
title: 'All Posts',
/* items: [
{ xtype: 'spacer' },
this.newButton
],*/
});
this.dockedItems = [ this.topToolbar ];
this.postList = new Ext.List({
store: myApp.stores.postStore,
grouped: true,
emptyText: '<div style="margin:5px;">No notes cached.</div>',
onItemDisclosure: true,
itemTpl: '<div class="list-item-title">{title}</div>' +
'<div class="list-item-narrative"><small>{body}</small></div>',
});
this.postList.on('disclose', function (record) {
this.onViewPost(record);
}, this),
this.items = [this.postList];
myApp.views.PostListView.superclass.initComponent.call(this);
},
onViewPost: function (record) {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewpost',
post: record
});
},
});
And here is the "detail" view that is called on disclosure:
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
title:'Single Post',
id:'postsingleview',
layout:'card',
style:'background:grey;',
initComponent: function () {
this.new1Button = new Ext.Button({
text: 'Back',
ui: 'back',
handler: this.onViewList,
scope: this,
dock:"left"
});
this.top1Toolbar = new Ext.Toolbar({
items: [
this.new1Button
],
title: 'Single Posts',
});
this.postSinglePanel = new Ext.Panel({
layout:'fit',
flex:1,
scroll: 'vertical',
style:'padding:10px;background:yellow;',
itemTpl: '<tpl for=".">' +
'<div class="list-item-narrative">{body}</div>' +
'</tpl>',
});
this.dockedItems = [ this.top1Toolbar, this.postSinglePanel ];
myApp.views.PostSingleView.superclass.initComponent.call(this);
},
onViewList: function () {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewlist',
});
},
});
And here is the controller that its talking to:
Ext.regController('masterController', {
'index': function (options) {
if (!myApp.views.mainView) {
myApp.views.mainView = new myApp.views.MainView();
}
myApp.views.mainView.setActiveItem(
myApp.views.postView
);
},
'viewpost': function (options) {
myApp.views.postSingleView.postSinglePanel.update(options.post);
myApp.views.postView.setActiveItem(
myApp.views.postSingleView,
{ type: 'slide', direction: 'left' }
);
},
});
myApp.controllers.masterController = Ext.ControllerManager.get('masterController');
When the data comes out, it looks similar to this:
http://i.imgur.com/QlQG8.png
(the black boxes are "redacted" content, no error code there).
In closing, I believe that the controller is "dumping" the data into "MyApp.views.PostSingleView" rather than formatting it as I request in the TPL, though I'm not sure how to fix it. Any and all help MUCH appreciated!
UPDATE: As requested, here is the RegModel:
Ext.regModel("CategoryModel", {
fields: [
{name: "id", type: "int"},
{name: "title", type: "string"},
{name: "body", type: "string"},
],
hasMany: {
model: 'Post',
name: 'posts'
}
});
And here is a sample of the json:
{
"status":"ok",
"post":{
"id":1037,
"type":"post",
"slug":"post-title",
"url":"http:\/\/localhost:8888\/jsontest\/PostTitle\/",
"status":"publish",
"title":"Post Title",
"title_plain":"Post Title",
"content":"<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<br \/>\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<\/p>\n<!-- PHP 5.x -->",
"excerpt":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat [...]",
"date":"2011-07-29 14:17:31",
"modified":"2011-08-30 01:33:20",
"categories":[
{
"id":87,
"slug":"the-category",
"title":"The Category",
"description":"",
"parent":17,
"post_count":5
}
],
"tags":[
],
"author":{
"id":2,
"slug":"tom",
"name":"tom",
"first_name":"tom",
"last_name":"",
"nickname":"",
"url":"",
"description":""
},
"comments":[
],
"attachments":[
],
"comment_count":0,
"comment_status":"open"
},
"previous_url":"http:\/\/localhost:8888\/jsontest\/next-post\/",
"next_url":"http:\/\/localhost:8888\/jsontest\/prev-post\/"
}
Use the tpl config option of the Ext.Panel not the itemTpl which doesn't exist.
As someone has mentioned before, be careful when using a Model instance and the update method, you will need to use the model's data property.
Try using this:
myApp.views.postSingleView.postSinglePanel.update(options.post.data);
the reason is that post does not actually expose the underlying data directly, you need to use the property data for that.
Also any particular reason why you are docking the postSinglePanel? I would be very careful using too many docked items as they are a known source of bugs and layout issues.
A simple way is to write your own method to update child panels (you can also see to override the default update method)
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
initComponent: function () {
// [...]
},
// [...]
myUpdate: function(data) {
this.postSinglePanel.update(data);
this.doComponentLayout(); // not sure if necessary...
}
});
and from your controller:
Ext.regController('masterController', {
// [...]
'viewpost': function (options) {
myApp.views.postSingleView.myUpdate(options.post.data); // note the .data
// [...]
},
});