I'm new to Phalcon, just trying to write my first application, and facing an issue that the documentation isn't very clear on, which is in regards to getting related information.
At the moment I have 1 controller, the User controller.
<?php
class UserController extends Phalcon\Mvc\Controller
{
public function homeAction()
{
$users = Users::query()
->where('id = :id:')
->bind(array('id' => '1'))
->execute();
$user = $users->getFirst();
$this->view->setVar('user', $users->getFirst());
$primaryStatus = Status::query()
->where('userId = :id:')
->bind(array('id' => '1'))
->execute();
$this->view->setVar('primaryStatus', $primaryStatus->getFirst());
$status = Status::query()
->where('userId != :id:')
->bind(array('id' => '1'))
->execute();
$this->view->setVar('status', $status);
}
}
And I have some models setup, Users, Attributes and UsersAttributes
and my view setup in volt.
This is my Attributes model
<?php
class Attributes extends Phalcon\Mvc\Model
{
public $id;
public $name;
public function initialize()
{
$this->hasMany('id', 'UsersAttributes', 'attributesId');
}
}
My Users model
<?php
/**
* Users class
*
* Represents Holla users
*
*/
class Users extends Phalcon\Mvc\Model
{
public $id;
public $name;
public $username;
public $password;
public $email;
public $active;
public $createdDate;
public function getSource()
{
return 'users';
}
public function initialize()
{
$this->hasMany('id', 'UsersAttributes', 'userId');
$this->hasManyToMany(
'id',
'UsersAttributes',
'userId', 'attributeId',
'Attributes',
'id'
);
}
}
and my UsersAttributes model
<?php
/**
* Users attributes class
*
* Represents Holla users attributes
*
* #Source('usersAttributes');
*
*/
class UsersAttributes extends Phalcon\Mvc\Model
{
public $id;
public $userId;
public $attributeId;
public $attributeValue;
public function getSource()
{
return 'usersAttributes';
}
public function initialize()
{
$this->belongsTo('userId', 'Users', 'id');
$this->belongsTo('attributeId', 'Attributes', 'id');
}
}
I have 3 tables
users
id e.g. 1
name e.g. andre
username e.g. andrefigueira
attributes
id e.g. 1
attributeName e.g. profileImage
attributeDefaultValue e.g. placeholder.jpg
usersAttributes
id e.g. 1
userId e.g. 1
attributeId e.g. 1
attributeValue e.g. andre.jpg
In my controller I am doing a query and assigning the first result to a view property which is the user property, but I cannot figure out how to access specific user attributes from the get related method implementation.
I'd like to be able to in my volt do something like:
The name of the attributes is defined in the attributes table, then assigned a value and user in the usersAttributes table.
{{ user.userAttributes.profileImage }}
How would I go about accomplishing this? I have searched through a lot of different posts and the documentation with little luck...
Thanks in advance
One to many relation returns the container of zero or more records:
{% for r in user.userAttributes %}
{{ r.profileImage }}
{% endfor %}
I've realised my error, everything was working as it should, Phalcon simply won't map my structure database in this way as I define an attribute name in the attributes table, but the user defined value in the usersAttributes table. Hence no way to map it by the standard way so I had to create a new method and instantiate it elsewhere to pass the parameters to my view.
The code I've used to solve the problem is in the Users model and simply appends the attributes as an object to the user result object.
public static function fetchUserAttributes($userId)
{
$modelsManager = Phalcon\DI::getDefault()->getModelsManager();
$phql = '
SELECT name, attributeValue
FROM Attributes
LEFT JOIN UsersAttributes
ON UsersAttributes.userId = :userId:
AND Attributes.id = UsersAttributes.attributeId
';
$rows = $modelsManager->executeQuery($phql, array('userId' => $userId));
$attributesObj = new \stdClass();
foreach($rows as $row)
{
$attributesObj->{$row['name']} = $row['attributeValue'];
}
return $attributesObj;
}
public function afterFetch()
{
//Attach user attributes
$this->attributes = Users::fetchUserAttributes($this->id);
}
Related
There are three database tables users, articles and a joining table article_users_comments, which holds the comment, the user id commented the article and the commented article id.
I can achieve the following thing with pure SQL join, but I want to do it with Eloquent, I thought that it would be quite easy, but I am kind of confused right now.
I have been trying different things, but it still doesn't work.
// User
class User extends Authenticatable implements MustVerifyEmail,CanResetPassword{
public function comments()
{
return $this->hasMany('App\ArticleComments');
}
}
// Article
class Article extends Model{
public function getArticles(){
$articles = Article::paginate(3);
return $articles;
}
public function getSingleArticle($title){
$article = Article::where('title','=',$title)->get();
return $article;
}
public function articleComments()
{
return $this->hasMany('App\ArticleComments');
}
}
// ArticleComments
class ArticleComments extends Model{
protected $table = 'article_users_comments';
public $timestamps = false;
public function article()
{
return $this->belongsTo('App\Article');
}
public function user()
{
$this->belongsTo('App\User');
}
}
// ArticleController(showing only the show method), which passes the data to the certain view
instantiating the Article Model
class ArticleController extends Controller{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($title)
{
$removeDashesFromUrl = str_replace('-',' ',$title);
$am = new Article();
$data = $am->getSingleArticle($removeDashesFromUrl);
return view('article',['article'=>$data]);
}
}
I want to get the comments and the users(which have commented the article) for a certain certain article.
You should set the foreign key in your articleComments and article relations:
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with _id. However, you may pass a custom key name as the second argument to the belongsTo method:
Article Model
public function articleComments()
{
return $this->hasMany('App\ArticleComments','commented_article_id');
}
ArticleComments Model
public function article()
{
return $this->belongsTo('App\Article','commented_article_id');
}
You can get the comments from a article using the relation:
$article = Article::find($id);
$article->articleComments; // This will return all comments for the given article
You could use a foreach loop and access each attribute from each comment:
foreach($article->articleComments as $comment)
{
echo $comment->id;
echo $comment->user->id;
echo $comment->user->username;
.
.
.
}
You can access the user and any of his attributes just calling the relation in your comment like i did above.
For more info: click here.
Note: i strongly recommend you changing your model name to Comment, we don't use model names in the plural, always in singular.
thank you view my question.
I would like to retrieve information on the tag table relation with the store with many-to-many when searching for a category
I created Store-table, Category-table, Tag-table.
The store-table and the category-table are connected by a many-to-many relation. The tag-table is the same.
I was able to search for categories and get information on businesses that are relation- ed, but I do not know how to get information on tags that are relations with stores.
So, I try this idea. search categories → get storeID from relation data→ storeID search → return shop data that hit.
However, I do not know how to get storeID in the store data acquired by category search
How can I write the code?
please help me.
sorry, bat my English.
App\Store
use Illuminate\Database\Eloquent\Model;
class Store extends Model
{
protected $fillable = ['name','location', 'price', 'open_time',
'closed_day'];
protected $table = 'stores';
public function photos(){
return $this->hasMany(StorePhoto::class);
}
public function categories(){
return $this->belongsToMany(Category::class,'category_store','category_id','store_id');
}
public function tags(){
return $this->belongsToMany(Tag::class, 'store_tag', 'tag_id', 'store_id');
}
}
App\Category
protected $fillable = ['store_id', 'category_id'];
public function stores()
{
return $this->belongsToMany(Store::class,'category_store','store_id','category_id');
}
App\Tag
protected $fillable = ['store_id', 'tag_id'];
public function stores()
{
return $this->belongsToMany(Store::class, 'store_tag', 'store_id', 'tag_id');
}
Resource/Category
class Category extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'store' => $this->stores,
];
}
}
web.php
use App\Category;
use App\Http\Resources\Category as CategoryResource;
Route::get("/store/api/category", function (Request $request) {
$search_category = $request->get('category_id');
return new CategoryResource(Category::find($search_category));
});
You can use dot notation to eager load nested relations:
$category = Category::with('stores.tags')->find($request->get('category_id'));
The tags will then be accessible on each Store model related to the Category:
// create a single flattened array of all the tags
$tags = $category->stores->flatMap->tags;
i have this table structure, project has one to many relation with rewards , rewards and shipping has many to many relation with pivot table reward_ship.
projects rewards shipping reward_ship
--------- -------- -------- ------------
id id id id
title amount location reward_id
amount project_id name ship_id
i am trying to extract one particular project details with all other associate tables data(rewards and shipping data using reward_ship table) in one query.
These is how i am trying
Projects Model
class Rewards extends Model {
public function projs(){
return $this->hasMany('App\Rewards');
}
public function rewds(){
return $this->belongsToMany('App\Shipping')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
public function shiplc(){
return $this->belongsToMany('App\Rewards')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
}
class Rewards extends Model {
public function proj() {
return $this->belongsTo('App\Projects');
}
}
Controller api class
Route::get('projects/{id}', function($id) {
$p = Projects::find($id);
$getd = Rewards::with('proj')
->where('rewards.project_id', '=', $p->id)
->get();
});
it doesn't work.
i search and tried many related model base query in larvel.
i know my implementation are wrong. Please suggest me to work out.
You can use Laravel 5.5 new feature API Resources.
It helps you to format the output of objects such as models or collections, to display attributes and also relationships.
So, you could do something like this in your ItemResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class Project extends Resource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
return [
'project_id' => $this->project_id,
'title' => $this->title,
'amount' => $this->amount,
// To access relationship attributes:
'rewards' => $this->rewards->load('shippings'),
];
}
}
Then in your controller, you just need to create a new Resource instance and pass the item object that you want to return:
use App\Http\Resources\Project as ProjectResource;
// some code
/**
* Show a single formatted resource.
*
* #param Project $project
* #return ProjectResource
*/
public function show($project)
{
return new ProjectResource($project);
}
// the rest of your code
The output should be the expected.
You have to fix the relationships that you have :
Projects Model :
public function rewards(){
return $this->hasMany('App\Rewards');
}
Rewards Model :
public function projects() {
return $this->belongsTo('App\Projects');
}
public function shippings(){
return $this->belongsToMany('App\Shipping','reward_ship', 'reward_id', 'ship_id');
}
Shipping model:
public function rewards(){
return $this->belongsToMany('App\Rewards','reward_ship', 'ship_id', 'reward_id');
}
After that you can call the relationships in the controller to eager load the wanted elements like this :
$project = Projects::with('rewards.shippings')
->where('id', $project_id)
->get();
And in the view you can loop over the rewards then get the shippings like this :
#foreach ($project->rewards as $reward)
<p>This is a reword {{ $reward->amount }}</p>
#foreach ($reward->shippings as $shipping)
<p>This is a shipping {{ $shipping->name }}</p>
#endforeach
#endforeach
class Project extends Model
{
public function rewds()
{
return $this->hasMany('App\Rewards');
}
public function shiplc()
{
return $this->hasManyThrough('App\Shipping', 'App\Rewards');
}
}
class Rewards extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
public function projs()
{
return $this->belongsTo('App\Project');
}
}
class Shipping extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
}
Route::get('projects/{id}', function($id) {
$p = Projects::with(['rewds', 'shiplc'])->find($id);
});
Project.php
class Project extends Model {
public function rewards() {
return this->hasMany(Reward::class, 'project_id', 'id');
}
}
Reward.php
class Reward extends Shipping {
public function shipping(){
return $this->belongsToMany(Shipping::class, 'reward_ship', 'reward_id', 'ship_id');
}
public function project(){
return $this->belongsTo(Project::class);
}
}
You can retrieve it like this:
$projectDetails = Project::where('id', $projectId)
->with(['rewards', 'rewards.shipping'])->get();
I'm developing a system in which i have different roles for accesing. The role is present in the Users table as an integer value.
I've created a model called roles and in this model i dont need a database connection or a table. I did set some constant values representing roles matching the role field in the user table.
So what's the problem ? It seems that i can't have relations with the roles model if this hasn't a table associated in the database.
This is my roles model:
class Roles extends Model {
const ROL_ADMINISTRADOR = 1;
const ROL_DIRECTOR = 2;
const ROL_PROFESOR = 3;
const ROL_RECOPILADOR = 4;
private $rol_id;
private $roles = [
self::ROL_ADMINISTRADOR => 'Administrador',
self::ROL_DIRECTOR => 'Director',
self::ROL_PROFESOR => 'Profesor',
self::ROL_RECOPILADOR => 'Recopilador'
];
/**
* RELACIONES
*/
public function _usuarios() {
return $this->hasMany(Usuarios::class, "rol", "rol_id");
}
/**
* FORMATEADORES
*/
/**
* FUNCIONES
*/
public function nombre() {
return $this->roles[$this->rol_id];
}
}
This is my users model
class Usuarios extends Authenticatable {
use Notifiable;
const STATUS_ACTIVO = 1;
const STATUS_INACTIVO = 0;
protected $table = 'usuarios';
protected $primaryKey = 'usuario_id';
/*
* RELACIONES
*/
public function _rol() {
return $this->hasOne(Roles::class, 'rol', 'rol_id');
}
public function _perfil() {
return $this->hasOne(Perfiles::class, "usuario", "usuario_id");
}
/*
* FORMATEADORES
*/
}
But i got this error
Base table or view not found: 1146
When i try to do this
<?= Auth::user()->_rol->nombre() ?>
=========================================================================
I think i've found the solution.
I did the following changes:
1.- in the roles model I did add the constructor method and customized it
public function __construct($rol) {
parent::__construct();
$this->rol_id = $rol;
}
2.- In the users model change the method to this
public function _rol() {
return new Roles($this->usuario_id);
}
There is a thing here: if the method is called like this '_rol' the model will think is about a relation and will required a relation response so is neccesary to call it this way '_rol()' (with the parenthesis)
<?= Auth::user()->_rol()->nombre() ?>
You only need the Role model if you have another table to store the roles.
If you, instead, have the role represented as a field in the users table, you can access it just doing:
$role = $user->role;
I suggest you to use https://github.com/artesaos/defender to manage roles and permitions.
I hope I can explain this clearly, apologies in advance if it is confusing. I have a goals table which hasOne of each of bodyGoalDescs, strengthGoalDescs and distanceGoalDescs as shown below
goals.php
class Goal extends BaseModel
{
protected $guarded = array();
public static $rules = array();
//define relationships
public function user()
{
return $this->belongsTo('User', 'id', 'userId');
}
public function goalStatus()
{
return $this->hasOne('GoalStatus', 'id', 'goalStatus');
}
public function bodyGoalDesc()
{
return $this->hasOne('BodyGoalDesc', 'id', 'bodyGoalId');
}
public function distanceGoalDesc()
{
return $this->hasOne('DistanceGoalDesc', 'id', 'distanceGoalId');
}
public function strengthGoalDesc()
{
return $this->hasOne('StrengthGoalDesc', 'id', 'strengthGoalId');
}
//goal specific functions
public static function yourGoals()
{
return static::where('userId', '=', Auth::user()->id)->paginate();
}
}
each of the three tables looks like this with the function details changed
class BodyGoalDesc extends BaseModel
{
protected $guarded = array();
public static $rules = array();
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'bodyGoalDescs';
//define relationships
public function goal()
{
return $this->belongsTo('Goal', 'bodyGoalId', 'id');
}
}
a goal has either a body goal, a strength goal, or a distance goal. I am having a problem with this method in the controller function
<?php
class GoalsController extends BaseController
{
protected $goal;
public function __construct(Goal $goal)
{
$this->goal = $goal;
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$thisgoal = $this->goal->find($id);
foreach ($this->goal->with('distanceGoalDesc')->get() as $distancegoaldesc) {
dd($distancegoaldesc->DistanceGoalDesc);
}
}
}
when I pass through goal 1 which has a distance goal the above method dies and dumps the Goal object with the details of goal 1 and an array of its relations including an object with DistanceGoalDes.
when I pass through goal 2 it passes through exactly the same as if I had passed through goal 1
if I dd() $thisgoal i get the goal that was passed through
what I want ultimately is a method that returns the goal object with its relevant goal description object to the view but this wont even show me the correct goal details not too mind with the correct relations
this function is now doing what I want it to do, I am sure there is a better way (besides the fact that its happening in the controller right now) and I would love to hear it.
public function show($id)
{
$thisgoal = $this->goal->find($id);
if (!$thisgoal->bodyGoalDesc == null) {
$goaldesc = $thisgoal->bodyGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('bodygoaldesc', $goaldesc);
} elseif (!$thisgoal->strengthGoalDesc == null) {
$goaldesc = $thisgoal->strengthGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('strengthgoaldesc', $goaldesc);
} elseif (!$thisgoal->distanceGoalDesc == null) {
$goaldesc = $thisgoal->distanceGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('distancegoaldesc', $goaldesc);
}
}