Laravel (API): I need to insert the post with Multiple Blog categories by using API Request (React) - api

I am trying to create a functionality for blog post which suppose to add by using front application which is built on react and my api which is built on Laravel (5.6),
I have tried couple of things, but unfortunately I am unable to figure out how can I attach multiple blog categories with single post
BlogPostAPIController.php
public function store(Request $request)
{
$BlogPosts = new BlogPosts;
$BlogPosts->tutor_id = $request->user()->tutor->id;
$BlogPosts->title = $request->title;
$BlogPosts->BlogCategories = $request->BlogCategories; /* Unknown column*/
$BlogPosts->slug = str_slug($request->title);
$BlogPosts->short_description = $request->short_description;
$BlogPosts->post_content = json_encode($request->post_content);
$BlogPosts->featured_image = $request->featured_image;
$BlogPosts->status = $request->status;
$BlogPosts->BlogCategories()->attach($request->blog_categories_id);
$BlogPosts->save();
return $BlogPosts::create($request->all());
}
BlogPostsModel.php
class BlogPosts extends Model{
public $table = 'blog_posts';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'tutor_id',
'title',
'slug',
'short_description',
'post_content',
'featured_image',
'status'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'tutor_id' => 'integer',
'title' => 'string',
'slug' => 'string',
'short_description' => 'string',
'post_content' => 'string',
'featured_image' => 'string',
'status' => 'string'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function tutor()
{
return $this->belongsTo(\App\Models\Tutor::class);
}
public function BlogCategories(){
return $this->belongsToMany(BlogCategories::class);
}
// Category.php
public function BlogPosts(){
return $this->hasMany(BlogPosts::class);
}
}
BlogCategoryBlogPost.php
Schema::create('blog_categories_blog_posts', function(Blueprint $table) {
$table->integer('blog_categories_id')->unsigned();
$table->integer('blog_posts_id')->unsigned();
$table->foreign('blog_categories_id')->references('id')->on('blog_categories')->onUpdate('cascade')->onDelete('cascade');
$table->foreign('blog_posts_id')->references('id')->on('blog_posts')->onUpdate('cascade')->onDelete('cascade');
});
API Response
Please find the screenshot for API response

You should save model before set relations, otherwise model doesn't have primary key (id) to set relations.
Better to use sync with belongsToMany relations (conveniently to update).
You should return saved model, now you create duplicate and return it.
Category belongsToMany Posts, and Post belongsToMany Categories.
Controller:
public function store(Request $request)
{
$BlogPosts = new BlogPosts;
$BlogPosts->tutor_id = $request->user()->tutor->id;
$BlogPosts->title = $request->title;
$BlogPosts->slug = str_slug($request->title);
$BlogPosts->short_description = $request->short_description;
$BlogPosts->post_content = json_encode($request->post_content);
$BlogPosts->featured_image = $request->featured_image;
$BlogPosts->status = $request->status;
$BlogPosts->save();
$BlogPosts->BlogCategories()->sync($request->blog_categories_id);
return $BlogPosts;
}
BlogPosts model:
public function BlogCategories(){
return $this->belongsToMany(BlogCategories::class, 'blog_categories_blog_posts');
}
BlogCategories model:
public function BlogPosts(){
return $this->belongsToMany(BlogPosts::class, 'blog_categories_blog_posts');
}

Related

Retrieve the attributes passed to a factory within the definition method - Laravel 9

I've been trying to find a way to retrieve the attributes passed to a factory within the definition method but have no luck, I first attempted to access the $this->states property (within the definition method) which returns a closure and then attempted to retrieve the attributes from there but have had no luck with this.
I am currently using the factories below:-
<?php
namespace Database\Factories;
use App\Models\Developer;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Developer>
*/
class DeveloperFactory extends Factory
{
/**
* Specify the corresponding model for the factory
*
* #var string $model
*/
protected $model = Developer::class;
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->firstName
];
}
public function configure()
{
$this->afterCreating(function (Developer $developer) {
User::factory()->create([
'userable_type' => $developer->getMorphClass(),
'userable_id' => $developer->id
]);
});
}
}
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
/**
* TODO: get any attributes that are passed into this factory
* e.g.userable_type, userable_id
*
* If these attributes are passed into the factory, stop the faker randomly generating a
* factory for a random user type and use the one passed into the factory
*/
$userableModel = (new $this->faker->userTypeModel)->factory()->create();
return [
'userable_type' => $userableModel->getMorphClass(),
'userable_id' => $userableModel->id,
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('admin1234'), // password
'remember_token' => Str::random(10)
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
}

JWTAuth always returns false in Laravel 6

I want to create a Laravel 6 backend with JWT authentication and when I want to sign in a user, JWTAuth always returns false, I google it but can't find any solution for it.
here are my project files codes,
this is my UserController
<?php
namespace App\Http\Controllers;
use App\Http\Requests\UserRequest;
use App\User;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Facades\JWTAuth;
class UserController extends Controller
{
public function signup(Request $request)
{
$user = new User();
$user->name = $request->input('name');
$user->email = $request->input('email');
$user->password = $request->input('password');
$user->save();
return response()->json(['message'=>'User Created Successfully!',$user],201);
}
public function signin(Request $request)
{
$credentials = [];
$credentials['email'] = $request->input('email');
$credentials['password'] = bcrypt($request->input('password'));
try{
if(!$token = JWTAuth::attempt($credentials)){
return response()->json(['error'=>'Invalid Credentials!'],401);
}
}catch(JWTException $e){
return response()->json(['error' => 'Could Not Create Token!'],500);
}
return response()->json(['token'=>$token],200);
}
}
User Model
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier() {
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims() {
return [];
}
public function setPasswordAttribute($password)
{
if ( !empty($password) ) {
$this->attributes['password'] = bcrypt($password);
}
}
}
And Api Route
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::post('/user','UserController#signup');
Route::post('/user/signin','UserController#signin');
when I want to sign in a user, JWTAuth:attempt($credentials), I don't know what I am missing or wrong?
Is there any solution?

How to validate two dimensional array in Yii2

How to validate two dimensional array in Yii2.
passenger[0][name] = bell
passenger[0][email] = myemail#test.com
passenger[1][name] = carson123
passenger[1][email] = carson###test.com
how to validate the name and email in this array
Thanks
Probably the most clean solution for validating 2-dimensional array is treating this as array of models. So each array with set of email and name data should be validated separately.
class Passenger extends ActiveRecord {
public function rules() {
return [
[['email', 'name'], 'required'],
[['email'], 'email'],
];
}
}
class PassengersForm extends Model {
/**
* #var Passenger[]
*/
private $passengersModels = [];
public function loadPassengersData($passengersData) {
$this->passengersModels = [];
foreach ($passengersData as $passengerData) {
$model = new Passenger();
$model->setAttributes($passengerData);
$this->passengersModels[] = $model;
}
return !empty($this->passengers);
}
public function validatePassengers() {
foreach ($this->passengersModels as $passenger) {
if (!$passenger->validate()) {
$this->addErrors($passenger->getErrors());
return false;
}
}
return true;
}
}
And in controller:
$model = new PassengersForm();
$model->loadPassengersData(\Yii::$app->request->post('passenger', []));
$isValid = $model->validatePassengers();
You may also use DynamicModel instead of creating Passanger model if you're using it only for validation.
Alternatively you could just create your own validator and use it for each element of array:
public function rules() {
return [
[['passengers'], 'each', 'rule' => [PassengerDataValidator::class]],
];
}
You may also want to read Collecting tabular input section in guide (unfortunately it is still incomplete).

Symfony2 - using form validation in REST API project

In a Symfony REST API project and we are implementing a validation for the params passed to the end points.
I'm trying to using forms for this purpose but they don't seem to work as expected.
Given this end point as example:
GET /users/
which accepts a companyId as param
we want that this param is required and integer.
The controller
public function getUsersAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user, array(
'method' => 'GET'
));
$form->handleRequest();
if ( ! $form->isValid()) {
// Send a 400
die('form is not valid');
} else {
die('form is valid');
}
}
The form type
class UserType extends FormType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('companyId', 'integer');
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults(array(
'data_class' => 'ApiBundle\Entity\User',
'csrf_protection' => false
));
}
/**
* #return string
*/
public function getName()
{
return ''; // if this is not empty, the form is not submitted at all
}
}
The validation.yml
ApiBundle\Entity\User:
properties:
companyId:
- Type:
type: integer
- NotBlank: ~
- NotNull: ~
The config.yml
framework:
validation: { enabled: true, enable_annotations: false }
The Problem
$form->isValid() in the controller is always true
Please replace with
$form->handleRequest();
to
$form->handleRequest($request);
I hope it will work.

Yii: change active record field names

I'm new to Yii and I have a table 'Student' with fields like 'stdStudentId', 'stdName', etc.
I'm making API, so this data should be returned in JSON. Now, because I want field names in JSON to just be like 'id', 'name', and I don't want all fields returned, i made a method in the model:
public function APIfindByPk($id){
$student = $this->findByPk($id);
return array(
'id'=>$student->stdStudentId,
'name'=>$student->stdName,
'school'=>$student->stdSchool
);
}
The problem is, stdSchool is a relation and in this situation, $student->stdSchool returns array with fields like schSchoolId, schName, etc. I don't want fields to be named like that in JSON, and also I don't want all the fields from School returned and I would like to add some fields of my own. Is there a way to do this in Yii, or I'll have to do it manually by writing methods like this?
I have been looking for the same thing. There is a great php lib named Fractal letting you achieve it: http://fractal.thephpleague.com/
To explain briefly the lib, for each of your models you create a Transformer that will be doing the mapping between your model attributes and the ones that need to be exposed using the api.
class BookTransformer extends Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
}
In the transformer you can also set the relation that this model have :
class BookTransformer extends TransformerAbstract
{
/**
* List of resources relations that can be used
*
* #var array
*/
protected $availableEmbeds = [
'author'
];
/**
* Turn this item object into a generic array
*
* #return array
*/
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
/**
* Here we are embeding the author of the book
* using it's own transformer
*/
public function embedAuthor(Book $book)
{
$author = $book->author;
return $this->item($author, new AuthorTransformer);
}
}
So at the end you will call
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Collection($books, new BookTransformer);
$json = $fractal->createData($resource)->toJson();
It's not easy to describe all the potential of fractal in one answer but you really should give it a try.
I'm using it along with Yii so if you have some question don't hesitate!
Since you are getting the values from the database using Yii active record, ask the database to use column aliases.
Normal SQL would be something like the following :
SELECT id AS Student_Number, name AS Student_Name, school AS School_Attending FROM student;
In Yii, you can apply Criteria to the findByPK() function. See here for reference : http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByPk-detail
$criteria = new CDbCriteria();
$criteria->select = 'id AS Student_Number';
$student = Student::model()->findByPk($id, $criteria);
Note that in order to use a column alias like that, you will have to define a virtual attribute Student_Number in your Student{} model.
Override the populateRecord() function of ActiveRecord can achieve this!
My DishType has 5 properties and override the populateRecord function Yii would invoke this when records fetched from db.
My code is here!
class DishType extends ActiveRecord
{
public $id;
public $name;
public $sort;
public $createTime;
public $updateTime;
public static function populateRecord($record, $row)
{
$pattern = ['id' => 'id', 'name' => 'name', 'sort' => 'sort', 'created_at' => 'createTime', 'updated_at' => 'updateTime'];
$columns = static::getTableSchema()->columns;
foreach ($row as $name => $value) {
$propertyName = $pattern[$name];
if (isset($pattern[$name]) && isset($columns[$name])) {
$record[$propertyName] = $columns[$name]->phpTypecast($value);
}
}
parent::populateRecord($record, $row);
}
}