Yii issue retrieving relational data - activerecord

I'm create a new table(s) in my Yii application thats going to be used as a relational table, just storing IDs, it's really simple, but i cannot manage to actually get any information passed through from the model, even though the IDs match. Can anyone see where i'm going wrong?
User Model (has many relations, but i've just included the one im having a problem with)
public function relations() {
return array(
'onsiteGroup' => array(self::HAS_MANY, 'EventAttendeesGroups', 'user_id'),
);
}
EventAttendeeGroups Model
class EventAttendeesGroups extends CActiveRecord
{
public function tableName()
{
return '{{event_attendees_groups}}';
}
public function rules()
{
return array(
array('user_id, group_id', 'required'),
array('user_id, group_id', 'numerical', 'integerOnly'=>true),
array('user_id, group_id', 'safe'),
array('id, user_id, group_id', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
'onsiteGroupName' => array(self::BELONGS_TO, 'EventAttendeesGroupName', 'group_id'),
);
}
public function attributeLabels()
{
return array(
'id' => 'ID',
'user_id' => 'User',
'group_id' => 'Group',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('user_id',$this->user_id);
$criteria->compare('group_id',$this->group_id);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
My Data is correct, the user id exists in the user table and in the EventAttendeeGroups table, yet if try the following in the user view gridview table, i get 'Not Set'
array(
'name' => 'group_id',
'type' => 'raw',
'value' => $model->onsiteGroup->group_id,
),
Can anyone see where i'm going wrong???

Are you getting an error? What is it outputting? Are you trying to render CGridView or what, and if yes is it formed?
One thought, are you sure
$model->onsiteGroup->group_id
is the object name and not
$model->onsiteGroupName->group_id
Just a thought.

Related

How to upload file in relationship hasOn<->belongsTo Laravel Backpack

Can be possible to store a file uploaded to a related table?
Scenario: I have a usres table in database and another one pictures. Users Model have the following function
public function picture()
{
return $this->hasOne(Picture::class);
}
And the Picture Model have the following function.
public function user_picture()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
Is possible to store the picture in pictures database table (id, user_id, img_path) from the UserCrudController store() function?
try something like this
public function store(Request $request)
{
Picture::create([
'user_id' => // get the user id from $request or auth()->user(),
'img_path' => $request->file('image')->store('images', 'public'),
]);
return // your view or something else
}
Let's say it is a registration form that need to insert an image. Instead of using the Picture model directly you can just do this :
public function store(Request $request)
{
$request->validate(...);
$user = User::create(...);
//It will ensure that the image belongs to the user.
$user->picture()->create([
'image_path' => $request->file('image')->store('images');
])
}
I resolved the issue with the following steps.
As per Laravel Backpack I added the input field in the Blade:
#include('crud::fields.upload', ['crud' => $crud, 'field' => ['name' => 'img1', 'label' => 'Image 1', 'type' => 'upload', 'upload'=> true, 'disk'=>'uploads', 'attributes' => ['id' => 'img1', 'capture' => 'user']]])
After this I added the function in the User Controller as follow:
$request->validate(['img1' => 'mimes:jpg,png,jpeg|max:5120']);
$fileModel = new Picture;
if($request->file()) {
$fileName1 = time().'_'.$request->img1->getClientOriginalName();
$filePath1 = $request->file('img1')->storeAs('uploads', $fileName1, 'public');
$fileModel->name = time().'_'.$request->img1->getClientOriginalName();
$fileModel->img1 = '/storage/' . $filePath1;
$fileModel->save();
}
With these lines of code I was able to store the related Picture with the User.
Thank you all for the guidelines.

How to set default value for a field in laravel `morphMany` relationship (not database tier)

I have a model File where save files of my app, it like:
class File{
public const IMAGE_TYPE = 'image';
public const AUDIO_TYPE = 'audio';
public const VIDEO_TYPE = 'video';
public const APPLICATION_TYPE = 'application';
protected $fillable = ['path', 'type', 'description', 'order', 'filable_type', 'filable_id'];
}
Suppose I have an Post model, it like:
class Post{
public function videos(){
return $this->morphMany(File::class, 'filable')
->where('type', File::VIDEO_TYPE);
}
public function images(){
return $this->morphMany(File::class, 'filable')
->where('type', File::IMAGE_TYPE);
}
}
When I get data of above relationships it's okay
But when I create a new file of post it is repetitive and easily make mistakes
$post->images()->create([
'path' => 'my-image.jpg',
'type' => File::IMAGE_TYPE,
]);
$post->videos()->create([
'path' => 'my-image.mp3',
'type' => File::VIDEO_TYPE,
]);
I want it look like:
$post->images()->create([
'path' => 'my-image.jpg',
]);
$post->videos()->create([
'path' => 'my-image.mp3',
]);
I don't need declare type per creating videos or images of a post.
How I can accomplish this!
Modal
// Change morphMany to hasMAny
public function videos()
{
return $this->hasMany(File::class, 'fileable')
->where('type', File::IMAGE_TYPE);
}
Controller
// You can do this
$vedioToCreate = $post->videos();
$vedioToCreate->path = 'my-image.mp3';
$vedioToCreate->save();
// Or you can do this
$post->videos()->create([
'path' => 'my-image.mp3',
]);

Property [user] does not exist on this collection instance

i'm developping a social app using React in the frontend and laravel in the backend.
I'm trying to receive all posts with their likes,users,comments. I have these relation ships:
1/ User model has many posts and Post model belongs to a user.
2/ Post model has many likes
3/ Post model has many comments and one comment belongs to a user.
When getting all posts back, im succefully getting its likes and users information, but for comments i wanna get the user's comment. So i did $posts->comments->user->user_name
And then, i got the error: Property [user] does not exist on this collection instance. But when i tried to get comments infos, it worked normally($posts->comments)
My comment relation in Post model:
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
My user relation in Comment Model:
public function user()
{
return $this->belongsTo('App\Models\User');
}
My method in PostController when i'm trying to get all posts:
public function allPosts()
{
$posts = Post::with('user','likes','comments')->get();
if($posts->count() < 1) {
return response()->json([
'success' => false,
'message' => 'There are no posts!'
]);
}else {
return response()->json([
'success' => true,
'data' => PostResource::collection($posts),
'message' => 'Succefully retreived all posts!'
]);
}
}
As you noticed i'm sending the Data through a Resource, so My PostResource's method :
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'user_id' => $this->user_id,
'content' => $this->content,
'image_path' => $this->image_path,
'user' => $this->user,
'likes' => $this->likes->count(),
'isLiked' => $this->likes->where('user_id', auth()->user()->id)->isEmpty() ? false : true,
'comment_user' => $this->comments->user->user_name,
'created_at' => $this->created_at->format('d/m/y'),
'updated_at' => $this->updated_at->format('d/m/y')
];
}
As i said, everything is okey, just for comment_user it says:Property [user] does not exist on this collection instance, and when i tried to get only comments info it worked:
'comments' => $this->comments,
Any help please? and thnx in advance.
Maybe you need to add relation user() to Post model?

ZF2 + Duplicate Form Validation on composite key

I have a Form having primary key on two fields (gid, bid). I need to add validation to block duplicate entries into database.
I have checked with ZF2 Solution for this . http://framework.zend.com/manual/2.2/en/modules/zend.validator.db.html#excluding-records . While this approach of handling composite keys is not look the ideal way, But still I am trying it because it look like only buil-in way. Now it require me to provide second field's value (value option in exclude), which is again a problem. As I am trying it
$inputFilter->add(array(
'name' => 'gid',
'required' => true,
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
'isEmpty' => 'required'
),
),
),
array (
'name' => 'Zend\Validator\Db\NoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
'messages' => array(
\Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
'exclude' => array(
'field' => 'bid',
'value' => [?],
),
)
),
)
));
How do I get this value, As Form is absolute separate Class/File than controller where I have the submitted form values. Is some better architecture solution of this problem exists Or Some hack to pass submitted field value to Form Class is only solution ?
Note : I am not in favor of Build My Validation Plugin for this task as short time is constraint for functionality.
You can do all the job in your form. To achieve that, you could define your forms as factories in your module Module.php.
Module.php
use MyNamespace\MyForm;
//NOTE THAT THE SERVICE MANAGER IS INJECTED. YOUR FORM COULD RECEIVE IT THROUGH THE CONSTRUCTOR
public function getServiceConfig()
{
return array(
'factories' => array(
'my_form' => function( $sm ) {
$form = new MyForm( $sm );
return $form;
},
),
);
}
When you want to use the form is as easy as use this code in your controller:
class MyController extends AbstractActionController
{
public function createAction() {
$form = $this->getServiceLocator()->get( 'my_form' ) );
(...)
}
}
And your MyForm.php
use Zend\Form\Form;
class MyForm extends Form
{
public $serviceManager, $request, $postData;
public function __construct( $serviceManager ) {
parent::__construct( null );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application')->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
This way you can get advantage of the Service Manager within your form. And the public postData, where you'll find the bid value you're looking for to build your NoRecordExists filter.
You could add the parameters to the getInputFilter, like this :
getInputFilter($gid, $bid)
And then on the controller, when you set the filter you pass the 2 parameters, and then just check as $form->isValid(); ...
Alternative try this:
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
),
),
I'm unsure on your use case. If you were to add a database entry the primary keys for that table would not be known until you insert anyway - If you have foreign key constraints you could handle the exception from the database.
I am not in favor of Build My Validation Plugin for this task
The validator is also not designed to validate multiple fields as they are attached to a form element on a 1-1 basis. You will therefore need to create your own.
The below example has NOT been tested, so take it as an example of the approach rather than working code.
The key bit is the isValid method.
namespace MyModule\Validator\Db;
use Zend\Validator\Db\NoRecordExists;
class CompositeNoRecordExists extends NoRecordExists
{
protected $field2;
protected $field2Value;
public function __construct($options = null)
{
parent::__construct($options);
if (array_key_exists('field2', $options)) {
$this->setField2($options['field2']);
} else {
throw new \BadMethodCallException('Missing field2 option!');
}
}
protected function setField2Value(array $context)
{
if (! isset($context[$this->field2])) {
throw new \BadMethodCallException('Unable to find value for field 2');
}
$this->field2Value = $context[$this->field2];
}
public function isValid($value)
{
// The isValid() method is actually given a 2nd argument called $context
// Which is injected by the inputFilter, via the input and into the validator chain
// $context contains all of RAW form element values, keyed by thier element name.
// Unfortunately due to the ValidatorInterface you are unable to add this to the method
// signature. So you will need to be 'creative':
$args = func_get_args();
if (isset($args[1]) && is_array($args[1])) {
$this->setField2Value($args[1]);
} else {
throw new \BadMethodCallException('Missing validator context');
}
return parent::isValid($value);
}
public function getSelect()
{
$select = parent::getSelect();
$select->where->equalTo($this->field2, $this->field2Value);
return $select;
}
}
Then all you would need to do is update the validator config, adding the field2 field name.
array (
'name' => 'MyModule\Validator\Db\CompositeNoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'field2' => 'bid',
'adapter' => $this->dbAdapter,
'messages' => array(
\Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
)
),

Symfony 2.0 validator, Blank() doesn't work

I am new on Symfony and I meet the following problem.
I'd like to generate a form without class.
I want to add a Blank() validator on one field.
See below.
class searchPropertyType extends AbstractType
{
public function getDefaultOptions(array $options)
{
$collectionConstraint = new Collection(array(
'keywords' => new blank()
));
return array('validation_constraint' => $collectionConstraint);
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('keywords')
->add('neighborhood')
->add('price_min')
->add('price_max')
->add('type')
->add('date_from' , 'date')
->add('date_to' , 'date')
;
}
public function getName()
{
return 'searchProperty';
}
}
The form is properly displayed but still, I can't send the form, I got a HTML5 alert saying that I must fill out this field.
ANy idea? I have been working on that the full day and it drives me crazy.
Thank you so much if you have time to help ;-)
To disable HTML5 client side validation add 'required' => false to getDefaultOptions:
public function getDefaultOptions(array $options)
{
$collectionConstraint = new Collection(array(
'keywords' => new blank()
));
return array(
'validation_constraint' => $collectionConstraint,
'required' => false
);
}
public function buildForm(FormBuilder $builder, array $options) {
$builder
->add('neighborhood','text',array('required' => false,))
->add('price_min','text',array('required' => false,))
->add('date_from', 'date', array('widget' => 'single_text', 'format' => 'dd MMM yyyy', 'required' => false))
);
}
Add required=>false
Hope this helps.

Resources