I am using ZF2 version-2.5.0 and doctrine version- ~2.5
I have three entities namely event, ranking and country as follows :
<?php
namespace SampleProject\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use SampleProject\Entity\Country;
use SampleProject\Entity\Ranking;
class Event
{
/**
*
* #ORM\Id
* #ORM\Column(name="eventID", type="integer", precision=0, nullable=false)
* #var int $eventID
*/
protected $eventID;
/**
* #ORM\Column(name="name", type="string", length=50, precision=0, nullable=false)
* #var string $name
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="SampleProject\Entity\Ranking", mappedBy="event")
* #var ArrayCollection $rankings
*/
protected $rankings;
/**
* #ORM\ManyToOne(targetEntity="SampleProject\Entity\Country", inversedBy="events", fetch="EXTRA_LAZY", cascade={"detach"})
* #ORM\JoinColumn(name="countryIso", referencedColumnName="countryIso", nullable=false)
* #var \SampleProject\Entity\Country $country
*/
protected $country;
/**
* Initializes doctrine collections, called from constructor in entity class
*/
protected function initializeCollections()
{
$this->rankings = new ArrayCollection();
}
public function setEventID($eventID)
{
$this->eventID = (int)$eventID;
return $this;
}
public function getEventID()
{
return $this->eventID;
}
public function setName($name)
{
$this->name = (string)$name;
return $this;
}
public function getName()
{
return $this->name;
}
public function setCountry(Country $country)
{
$this->country = $country;
return $this;
}
public function getCountry()
{
return $this->country;
}
public function addRanking(Ranking $ranking)
{
$this->rankings[] = $ranking;
return $this;
}
public function getRankings()
{
return $this->rankings;
}
}
?>
<?php
namespace SampleProject\Country;
use SampleProject\Entity\Event;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
class Country
{
/**
*
* #ORM\Id
* #ORM\Column(name="countryIso", type="string", length=3, precision=0, nullable=false)
* #var string $countryIso
*/
protected $countryIso;
/**
* #ORM\Column(name="name", type="string", length=50, precision=0, nullable=false)
* #var string $name
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="SampleProject\Entity\Event", mappedBy="country", fetch="EXTRA_LAZY")
* #var ArrayCollection $events
*/
protected $events;
/**
* Initializes doctrine collections, called from constructor in entity class
*/
protected function initializeCollections()
{
$this->events = new ArrayCollection();
}
public function setCountryIso($countryIso)
{
$this->countryIso = (string) $countryIso;
return $this;
}
public function getCountryIso()
{
return $this->countryIso;
}
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function addEvent(Event $event)
{
$this->events->add($event);
return $this;
}
public function getEvents()
{
return $this->events;
}
}
?>
<?php
namespace SampleProject\Ranking;
use Doctrine\ORM\Mapping as ORM;
use SampleProject\Entity\Event;
class Ranking
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Column(type="integer", precision=0, nullable=false)
* #var int $rankingID
*/
protected $rankingID;
/**
* #ORM\Column(name="rank", type="integer", precision=0, nullable=true)
* #var int $rank
*/
protected $rank;
/**
* #ORM\ManyToOne(targetEntity="SampleProject\Entity\Event", inversedBy="rankings", fetch="LAZY")
* #ORM\JoinColumn(name="eventID", referencedColumnName="eventID", nullable=false)
* #var \SampleProject\Entity\Event $event
*/
protected $event;
/**
* #ORM\Column(name="locale", type="string", length=5, precision=0, nullable=true)
* #var string $locale
*/
protected $locale;
public function getRankingID()
{
return $this->rankingID;
}
public function setRank($rank)
{
$this->rank = (int) $rank;
return $this;
}
public function getRank()
{
return $this->rank;
}
public function setEvent(Event $event)
{
$this->event = $event;
return $this;
}
public function getEvent()
{
return $this->event;
}
public function getLocale()
{
return $this->locale;
}
public function setLocale($locale)
{
$this->locale = $locale;
}
}
?>
One event belongs to one country and one country can have multiple events.
One event have multiple rankings depending on locale i.e. (en, nl etc.).
I am using ZF2 and doctrine to get listing of events order by rankings in ascending order.
Internally it executes following query to show events listing:
SELECT a0_.name AS name_3, a0_.countryIso AS countryIso_37, COALESCE(a1_.rank, 99999) AS sclr_34
FROM Event a0_
LEFT JOIN Ranking a1_ ON a0_.eventID = a1_.eventID AND (a1_.locale = 'en' OR a1_.locale IS NULL)
INNER JOIN Country a2_ ON a0_.countryIso = a2_.countryIso
GROUP BY a0_.eventID
ORDER BY sclr_34 ASC, a0_.name ASC
So the result is something like as follows :
event1 BEL 1
event2 AUS 2
event3 AUS 3
event4 AUS 4
event5 NLD 5
event6 NLD 6
event7 ESP 7
But now, I want to display events per event per country. So the output will be like :
event1 BEL 1
event2 AUS 2
event5 NLD 5
event7 ESP 7
So, I believe query will be now like below :
SELECT * FROM (
SELECT a0_.name AS name_3, a0_.countryIso AS countryIso_37, COALESCE(a1_.rank, 99999) AS sclr_34
FROM Event a0_
LEFT JOIN Ranking a1_ ON a0_.eventID = a1_.eventID AND (a1_.locale = 'en' OR a1_.locale IS NULL)
INNER JOIN Country a2_ ON a0_.countryIso = a2_.countryIso
GROUP BY a0_.eventID
ORDER BY sclr_34 ASC, a0_.name ASC
) as t
GROUP BY t.countryIso_37 ORDER BY t.sclr_34 ASC limit 6;
But, with ZF2 and doctrine I am unable to prepare above query.
How can I achieve this using ZF2 and doctrine?
Related
I have Laravel mix installed on my server. there is a chat part on website and I use some kind of class :
class ActivityCell extends Component {
getTimestamp() {
const {message} = this.props;
return (
<span className="font-weight-semi-bold">
{utcDateCalendarTime(message.created_at)}
</span>
);
}
And here is my AppServiceProvider.php file :
<?php
namespace App\Providers;
use Illuminate\Http\Resources\Json\Resource;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function boot()
{
setlocale(LC_ALL, Config::get('app.lc_all'));
Carbon::setLocale(Config::get('app.locale'));
}
public function register()
{
$this->registerPlugins();
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->bootDatabase();
$this->bootResource();
}
/**
* Boot database schema
*
* #return void
*/
private function bootDatabase()
{
Schema::defaultStringLength(191);
}
/**
* Boot resource
*
* #return void
*/
private function bootResource()
{
Resource::withoutWrapping();
}
/**
* Register plugins
*
* #return void
*/
private function registerPlugins()
{
$pluginDirs = File::directories(base_path('app/Plugins'));
foreach ($pluginDirs as $pluginDir) {
$class = "App\\Plugins\\" . basename($pluginDir) . "\\PluginServiceProvider";
if (class_exists($class) && is_subclass_of($class, ServiceProvider::class)) {
$this->app->register($class);
}
}
}
}
I tried to put setlocale(LC_TIME, 'tr'); on top of the class file but there is no success. Then tried to use carbon in order to make the date is viewed in different languages when I change the website language.
I added the following codes in app/config.php :
'locale' => env('APP_LOCALE', 'az'),
'lc_all' => env('APP_LC_ALL', 'az_AZ.UTF-8'),
and added following to the env file :
APP_LOCALE = az
APP_LC_ALL = az_AZ.UTF-8
in both methods, I was not successful. I am pretty sure that I am doing a mistake somewhere but can not find where exactly. Maybe I am missing to add something else to add. Any help would be highly appreciated.
EDIT : Adding Chat.php :
<?php
namespace App\Models;
use App\Events\ChatParticipationChanged;
use App\Events\ChatUpdated;
use App\Http\Resources\ChatMessage as ChatMessageResource;
use App\Http\Resources\MarketplaceTrade as MarketplaceTradeResource;
use ArrayObject;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use JSsVPSDioNXpfRC;
use DateTimeInterface;
class Chat extends Model
{
protected $lastMessageAttribute;
protected $lastMarketplaceTradeAttribute;
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* The event map for the model.
*
* #var array
*/
protected $dispatchesEvents = [
'updated' => ChatUpdated::class
];
/**
* Indicates if the IDs are auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
/**
* Get the route key for the model.
*
* #return string
*/
protected function serializeDate(DateTimeInterface $date)
{
return $date->translatedFormat('A B M');
}
public function getRouteKeyName()
{
return 'id';
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function creator()
{
return $this->belongsTo(User::class, 'creator_id', 'id');
}
/**
* Participants for this chat
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function participants()
{
return $this->hasMany(ChatParticipant::class, 'chat_id', 'id');
}
/**
* Messages for this chat
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function messages()
{
return $this->hasMany(ChatMessage::class, 'chat_id', 'id');
}
/**
* Update user's participation record
*
* #param User $user
*/
public function updateParticipation($user)
{
$this->participants()->where('user_id', $user->id)
->update(['last_read_at' => now()]);
broadcast(new ChatParticipationChanged($this, $user));
}
/**
* All marketplace trades hosted by this chat
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function marketplaceTrades()
{
return $this->hasMany(MarketplaceTrade::class, 'chat_id', 'id')
->has('buyer')->has('seller');
}
/**
* #return Model|\Illuminate\Database\Eloquent\Relations\HasMany|mixed|object|null
*/
public function getLatestMarketplaceTrade()
{
if (!isset($this->lastMarketplaceTradeAttribute)) {
$trade = $this->marketplaceTrades()->latest()->first();
$this->lastMarketplaceTradeAttribute = new MarketplaceTradeResource($trade);
}
return $this->lastMarketplaceTradeAttribute;
}
/**
* Last chat message
*
* #return ChatMessageResource|ArrayObject|mixed
*/
public function getLatestMessage()
{
if (!isset($this->lastMessageAttribute)) {
$message = $this->messages()->latest()->first();
if ($message) {
$this->lastMessageAttribute = new ChatMessageResource($message);
} else {
$this->lastMessageAttribute = new ArrayObject();
}
}
return $this->lastMessageAttribute;
}
/**
* #param User $user
* #return array
*/
public function getParticipation($user)
{
$participant = $this->participants()
->where('user_id', $user->id)->without('user')
->first();
$unreadMessagesCount = ($participant && $participant->last_read_at) ?
$this->messages()->where('user_id', '!=', $user->id)
->where('created_at', '>', $participant->last_read_at)
->count() :
$this->messages()->where('user_id', '!=', $user->id)
->count();
return [
'user_id' => $user->id,
'unread_messages_count' => $unreadMessagesCount
];
}
/**
* If user should be allowed in this chat
*
* #param User $user
* #return bool
*/
public function shouldAllowUser($user)
{
$isParticipant = $this->participants()
->where('user_id', $user->id)->exists();
return (
$isParticipant ||
$user->can('moderate_chats')
);
}
/**
* #return string
*/
public function attachmentsDir()
{
return "chats/{$this->id}/message-attachments";
}
}
The problem is on your namespace :
// Using PHP callable syntax
use Carbon\Carbon;
Or,
// Using string syntax
\Carbon\Carbon::setLocale('ru');
You also need to use translatedFormat() method on your blade for use the translate format, like :
{{ Carbon\Carbon::now()->translatedFormat('A B M') }} // утра 428 фев
You can use serializeDate() method on your model, to change timestamp column as a translated dataTime format :
use DateTimeInterface;
protected function serializeDate(DateTimeInterface $date)
{
return $date->translatedFormat('A B M');
}
I want to combine two separate pagination model in laravel, but errors in the view and paging does not work.
my controller code ,I also tried different methods, data comes but paging is not my goal paging
<?php
namespace App\Http\Controllers\Frontend\News;
use App\Http\Controllers\Controller;
use App\Models\Blog;
use App\Models\Company\CompanyEvent;
class NewsController extends Controller
{
function news()
{
$blogs = Blog::sort()->with('company')->paginate(15);
$events = CompanyEvent::sort()->with('company')->paginate(15);
$events=collect($events)->merge($blogs);
return view('news.news',compact('events'));
}
function detail()
{
return "detail";
}
}
blog model
<?php
namespace App\Models;
use App\Models\Company\Company;
use App\Models\Interfaces\CreatedAt;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Http\Request;
/**
* Class Blog
* #package App\Models
* #mixin Builder
* #property boolean $active
* #property int $company_id
* #property string $title
* #property string $url
* #property string $context
* #property string $tags
* #property string $main
* #property string $seo_title
* #property string seo_description
* #property string $seo_keyword
* #property string $image
* #property-read CreatedAt|Carbon $created_at
* #property-read CreatedAt|Carbon $updated_at
* #property-read CreatedAt|Carbon $deleted_at
* #method static Builder|Blog find(int $id)
* #method static Builder|Blog where($column, $operator = null, $value = null, $boolean = 'and')
* #method static Builder|Blog findOrFail($id)
* #method static Builder|Blog active()
* #method Builder|Blog filter(Request $request) bind to scopeFilter method
* #method static Builder|Blog sort() laravel query bind to scopeSort method
* #method static Builder|Blog latest() laravel query bind to scopeSort method
*
*/
class Blog extends Model
{
use SoftDeletes;
protected $table = 'blogs';
/**
* #return bool
*/
public function isActive(): bool
{
return (bool)$this->active;
}
/**
* #param bool $save
* #return bool
*/
public function toggleActive($save = false)
{
$this->active = !$this->active;
if ($save == true)
return $this->save();
return false;
}
/**
* #return MorphToMany
*/
function comments()
{
return $this->morphToMany('App\Models\Blog', 'commentable');
}
/**
* #return string
*/
function getAgoTimeAttribute()
{
return Carbon::parse($this->created_at)->diffForHumans();
}
/**
* #param $value
* #return array
*
*/
function getTagsAsArrayAttribute($value)
{
return explode(',', $this->tags);
}
/**
* #param Builder|Blog $query
* #return mixed
*
*/
function scopeActive($query)
{
return $query->where('active', 1);
}
/**
* #return BelongsTo
*/
function company()
{
return $this->belongsTo(Company::class, 'company_id', 'id');
}
/**
* #return string
*/
function getTimeAgoAttribute()
{
return Carbon::parse($this->created_at)->diffForHumans();
}
/**
* #return false|string
*/
function getShortContextAttribute()
{
return substr($this->context, 0, 250);
}
/**
* #param Blog|Builder $query
* #param Request $request
* #return mixed
*/
function scopeFilter($query, $request)
{
$requests = $request->except('page');
foreach ($requests as $key => $val)
$query = $query->where($key, 'like', '%' . $val . '%');
return $query;
}
/**
* #param Builder|Blog $query
* #return mixed
*/
function scopeSort($query)
{
return $query->orderBy('created_at', 'desc');
}
}
company event model
<?php
namespace App\Models\Company;
use App\Calendar\Day\Day;
use App\Calendar\Month\Month;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
/**
* Class CompanyEvent
* #mixin Builder
* #package App\Models\Company
* #property \DateTime $date
* #method static Builder|CompanyEvent get()
* #method static Builder|CompanyEvent find($id)
* #method static Builder|CompanyEvent findOrFail($id)
* #method static Builder|CompanyEvent active() bind to scopeActive
* #method static Builder|CompanyEvent sort()
* #method static Builder|CompanyEvent latest()
*
*/
class CompanyEvent extends Model
{
use SoftDeletes;
protected $table = 'company_events';
/**
* get day name from date column
* #return string
*
*/
function getDayNameAttribute()
{
$dayIndex = (int)date('w', strtotime($this->date));
return ucfirst(Day::DAY_NAMES[$dayIndex]);
}
/**
* get month from date column
* #return string
*/
function getMonthAttribute()
{
$monthIndex = (int)date('m', strtotime($this->date));
return ucfirst(Month::MONTH_NAMES[$monthIndex - 1]);
}
/**
* #return false|string
*/
function getDayAttribute()
{
return date('d', strtotime($this->date));
}
/**
* #return bool
*
*/
function getIsExpireDateAttribute()
{
$date = date('Y-m-d', strtotime($this->date));
$todayDateAsTime = strtotime(date('Y-m-d'));
$eventDateAsTime = strtotime($date);
if ($todayDateAsTime > $eventDateAsTime)
return true;
return false;
}
/**
* #return bool
*
*/
function getIsEventTodayAttribute()
{
$date = date('Y-m-d', strtotime($this->date));
$todayDateAsTime = strtotime(date('Y-m-d'));
$eventDateAsTime = strtotime($date);
return (boolean)($eventDateAsTime == $todayDateAsTime);
}
/**
* #return string
*/
function getAgoTimeAttribute()
{
return Carbon::parse($this->date)->diffForHumans();
}
/**
* #return BelongsTo
*/
function company()
{
return $this->belongsTo(Company::class, 'company_id', 'id');
}
/**
* #param Builder|CompanyEvent $query
* #return mixed
*/
function scopeActive($query)
{
return $query->where('active', 1);
}
/**
* #param Builder|CompanyEvent $query
* #return mixed
*/
function scopeSort($query)
{
return $query->orderBy('created_at','desc');
}
}
I also tried different methods, data comes but paging is not my goal paging
my view code
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Mr. Burhan</title>
</head>
<body>
{{$events->total()}} adet bulundu
<ul>
#foreach( $events as $value )
<li>{{$value}}</li>
#endforeach
</ul>
{{$events->appends(request()->all())->render()}}
</body>
</html>
I have a problem creating a form by including a formType that are 2 related entities and that must be combined with a CollectionType.
I use the library jquery.collection for CollectionType ( http://symfony-collection.fuz.org/symfony3/ )
My entities
Product
namespace BBW\ProductBundle\Entity\Product;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* Product
*
* #ORM\Table(name="product_product")
* #ORM\Entity(repositoryClass="BBW\ProductBundle\Repository\Product\ProductRepository")
*/
class Product
{
use ORMBehaviors\Translatable\Translatable;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
* #ORM\ManyToMany(targetEntity="BBW\ProductBundle\Entity\Attribute\AttributeGroup", inversedBy="products", fetch="EAGER")
* #ORM\JoinTable(name="product_join_attribute_group")
*/
private $attributeGroups;
/**
* #var array
* #ORM\ManyToMany(targetEntity="BBW\ProductBundle\Entity\Attribute\Attribute", inversedBy="products", fetch="EAGER")
* #ORM\JoinTable(name="product_join_attribute")
*/
private $attributes;
/**
* Constructor
*/
public function __construct()
{
$this->attributeGroups = new \Doctrine\Common\Collections\ArrayCollection();
$this->attributes = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add attributeGroup
*
* #param \BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup
*
* #return Product
*/
public function addAttributeGroup(\BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup)
{
$this->attributeGroups[] = $attributeGroup;
return $this;
}
/**
* Remove attributeGroup
*
* #param \BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup
*/
public function removeAttributeGroup(\BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup)
{
$this->attributeGroups->removeElement($attributeGroup);
}
/**
* Get attributeGroups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAttributeGroups()
{
return $this->attributeGroups;
}
/**
* Add attribute
*
* #param \BBW\ProductBundle\Entity\Attribute\Attribute $attribute
*
* #return Product
*/
public function addAttribute(\BBW\ProductBundle\Entity\Attribute\Attribute $attribute)
{
$this->attributes[] = $attribute;
return $this;
}
/**
* Remove attribute
*
* #param \BBW\ProductBundle\Entity\Attribute\Attribute $attribute
*/
public function removeAttribute(\BBW\ProductBundle\Entity\Attribute\Attribute $attribute)
{
$this->attributes->removeElement($attribute);
}
/**
* Get attributes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAttributes()
{
return $this->attributes;
}
}
AttributeGroup
namespace BBW\ProductBundle\Entity\Attribute;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* AttributeGroup
*
* #ORM\Table(name="product_attribute_group")
* #ORM\Entity(repositoryClass="BBW\ProductBundle\Repository\Attribute\AttributeGroupRepository")
*/
class AttributeGroup
{
use ORMBehaviors\Translatable\Translatable;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\OneToMany(targetEntity="BBW\ProductBundle\Entity\Attribute\Attribute", mappedBy="attributeGroup", cascade={"persist", "remove"}, fetch="EAGER")
* #ORM\JoinColumn(name="attribute_id")
*/
private $attributes ;
/**
* #var array
* #ORM\ManyToMany(targetEntity="BBW\ProductBundle\Entity\Product\Product", mappedBy="attributeGroups", cascade={"persist"}, fetch="EAGER")
*/
private $products;
/**
* Constructor
*/
public function __construct()
{
$this->attributes = new \Doctrine\Common\Collections\ArrayCollection();
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add attribute
*
* #param \BBW\ProductBundle\Entity\Attribute\Attribute $attribute
*
* #return AttributeGroup
*/
public function addAttribute(\BBW\ProductBundle\Entity\Attribute\Attribute $attribute)
{
$this->attributes[] = $attribute;
return $this;
}
/**
* Remove attribute
*
* #param \BBW\ProductBundle\Entity\Attribute\Attribute $attribute
*/
public function removeAttribute(\BBW\ProductBundle\Entity\Attribute\Attribute $attribute)
{
$this->attributes->removeElement($attribute);
}
/**
* Get attributes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Add product
*
* #param \BBW\ProductBundle\Entity\Product\Product $product
*
* #return AttributeGroup
*/
public function addProduct(\BBW\ProductBundle\Entity\Product\Product $product)
{
$this->products[] = $product;
return $this;
}
/**
* Remove product
*
* #param \BBW\ProductBundle\Entity\Product\Product $product
*/
public function removeProduct(\BBW\ProductBundle\Entity\Product\Product $product)
{
$this->products->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
}
Attributes
namespace BBW\ProductBundle\Entity\Attribute;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* Attribute
*
* #ORM\Table(name="product_attribute")
* #ORM\Entity(repositoryClass="BBW\ProductBundle\Repository\Attribute\AttributeRepository")
*/
class Attribute
{
use ORMBehaviors\Translatable\Translatable;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\ManyToOne(targetEntity="BBW\ProductBundle\Entity\Attribute\AttributeGroup", inversedBy="attributes", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinColumn(name="attribute_group_id")
*/
private $attributeGroup ;
/**
* #var array
* #ORM\ManyToMany(targetEntity="BBW\ProductBundle\Entity\Product\Product", mappedBy="attributes", cascade={"persist"}, fetch="EAGER")
*/
private $products;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set attributeGroup
*
* #param \BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup
*
* #return Attribute
*/
public function setAttributeGroup(\BBW\ProductBundle\Entity\Attribute\AttributeGroup $attributeGroup = null)
{
$this->attributeGroup = $attributeGroup;
return $this;
}
/**
* Get attributeGroup
*
* #return \BBW\ProductBundle\Entity\Attribute\AttributeGroup
*/
public function getAttributeGroup()
{
return $this->attributeGroup;
}
/**
* Constructor
*/
public function __construct()
{
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add product
*
* #param \BBW\ProductBundle\Entity\Product\Product $product
*
* #return Attribute
*/
public function addProduct(\BBW\ProductBundle\Entity\Product\Product $product)
{
$this->products[] = $product;
return $this;
}
/**
* Remove product
*
* #param \BBW\ProductBundle\Entity\Product\Product $product
*/
public function removeProduct(\BBW\ProductBundle\Entity\Product\Product $product)
{
$this->products->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
}
Explanation
My product must belong to an attribute group and must contain attributes. I have a relationship between my AttributeGroup entity and a Relationship with Attribute.
My Entity AttributeGroup has a relationship with Attribute (functional).
Form Types
In my form I have a CollectionType with another formType as entry_type I have created with two entity types (AttributeGroups / Attributes)
FormType for product
namespace BBW\ProductBundle\Form\Product;
use A2lix\TranslationFormBundle\Form\Type\TranslationsType;
use BBW\CoreBundle\FormTypes\SwitchType;
use BBW\MediaBundle\Transformers\MediaTransformer;
use BBW\ProductBundle\Form\Attribute\Type\AttributeType;
use Doctrine\ORM\Mapping\Entity;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductEditType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$locale = $options['int_service'];
$builder
->add('attributes', CollectionType::class, array(
'entry_type' => AttributeType::class,
'entry_options' => array(
'label' => false
),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'required' => false,
'attr' => array(
'class' => 'attributes-selector'
),
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BBW\ProductBundle\Entity\Product\Product',
'int_service' => ['fr'],
'translation_domain' => 'ProductBundle'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'bbw_productbundle_edit_product';
}
}
AttributeType
/**
* Form Type: Fields add in product edit form
*/
namespace BBW\ProductBundle\Form\Attribute\Type;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AttributeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('attributeGroups', EntityType::class, array(
'label' => false,
'class' => 'BBW\ProductBundle\Entity\Attribute\AttributeGroup',
'choice_label' => 'translate.name',
'attr' => array(
'class' => 'choiceAttributeGroup'
),
))
->add('attributes', EntityType::class, array(
'label' => false,
'class' => 'BBW\ProductBundle\Entity\Attribute\Attribute',
'choice_label' => 'translate.name',
'attr' => array(
'class' => 'choiceAttributes'
)
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BBW\ProductBundle\Entity\Product\Product',
'int_service' => ['fr'],
'translation_domain' => 'ProductBundle'
));
}
}
Explanation
The two entities (AttributeGroups / Attributes) are two linked drop-down lists. When I select a group, I must display the data of this group in the second drop-down list. This part works well. I can duplicate as much as I want (with the CollectionType).
First problem when i submit the form:
"Could not determine access type for property "attributeGroups" ".
Second problem when i set "mapped => false" in my two entities:
"Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "BBW\ProductBundle\Entity\Product\Product#$attributes", got "BBW\ProductBundle\Entity\Product\Product" instead."
Screeshoots dump/form
Conclusion
I think my problem is a mapping problem, having tested a lot of code and explanation on the symfony doc or other site, I could not solve my problem. If anyone could help me out and explain the good work of a collectionType with 2 entity and if that is possible. If you have examples of codes I am taker too.
Thank you in advance for your help.
I try to learn Doctrine2 now so I created a trivial Entity (actually I got it from tutorial):
<?php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Product {
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name;
return $this;
}
}
I also created an action to create and persist such product:
public function createProductAction() {
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$em->getConnection()
->getConfiguration()
->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
$product = new Product();
$product->setName("Test product");
$em->persist($product);
$em->flush();
echo "Created product with ID ".$product->getId();
}
Of course before test I've ran a command to create db scheme (and checked that it's actually created). Simillar code for User runs smoothly but this action reports following:
"START TRANSACTION" INSERT INTO Product (name) VALUES (?)
array (size=1)
1 => null
array (size=1)
1 => string 'string' (length=6)
"ROLLBACK"
What's wrong?? Is there anyway to debug it somehow?? :|
I'm trying to send a post request including two timestamps to my REST api.
The problem is that the timestamps are marked as invalid. "This value is not valid."
What am I doing wrong?
This is the request:
POST http://localhost:8000/app_test.php/api/projects/1/tasks/1/timetrackings
Accept: application/json
Content-Type: application/json
{"timeStart":1390757625,"timeEnd":1390757625,"projectMember":1}
The Controller looks as follows:
class MemberController extends BaseApiController implements ClassResourceInterface
{
public function postAction($projectId, $taskId, Request $request)
{
/** #var EntityManager $em */
$em = $this->getDoctrine()->getManager();
$this->findProject($em, $projectId);
$task = $this->findTask($em, $projectId, $taskId);
$request->request->add(array(
'task' => $taskId,
));
$form = $this->createForm(new TimeTrackType(), new TimeTrack());
$form->submit($request->request->all());
if ($form->isValid())
{
/** #var TimeTrack $tracking */
$tracking = $form->getData();
$task->addTimeTrack($tracking);
$em->flush();
return $this->redirectView(
$this->generateUrl('api_get_project_task_timetracking', array(
'projectId' => $projectId,
'taskId' => $taskId,
'trackingId' => $tracking->getId(),
)),
Codes::HTTP_CREATED
);
}
return View::create($form, Codes::HTTP_BAD_REQUEST);
}
}
The TimeTrackType class:
namespace PMTool\ApiBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TimeTrackType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('timeStart', 'datetime', array(
'input' => 'timestamp',
))
->add('timeEnd', 'datetime', array(
'input' => 'timestamp',
))
->add('projectMember')
->add('task')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'PMTool\ApiBundle\Entity\TimeTrack',
'csrf_protection' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'timetrack';
}
}
The entity class:
namespace PMTool\ApiBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use \DateTime;
/**
* TimeTrack
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="PMTool\ApiBundle\Entity\TimeTrackRepository")
*/
class TimeTrack
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var DateTime
*
* #ORM\Column(name="timeStart", type="datetime")
*/
private $timeStart;
/**
* #var DateTime
*
* #ORM\Column(name="timeEnd", type="datetime")
*/
private $timeEnd;
/**
* #var ProjectMember
*
* #ORM\ManyToOne(targetEntity="ProjectMember")
*/
private $projectMember;
/**
* #var Task
*
* #ORM\ManyToOne(targetEntity="Task", inversedBy="timeTracks")
* #ORM\JoinColumn(name="taskId", referencedColumnName="id")
*/
private $task;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set timeStart
*
* #param DateTime $timeStart
* #return TimeTrack
*/
public function setTimeStart($timeStart)
{
$this->timeStart = $timeStart;
return $this;
}
/**
* Get timeStart
*
* #return DateTime
*/
public function getTimeStart()
{
return $this->timeStart;
}
/**
* Set timeEnd
*
* #param DateTime $timeEnd
* #return TimeTrack
*/
public function setTimeEnd($timeEnd)
{
$this->timeEnd = $timeEnd;
return $this;
}
/**
* Get timeEnd
*
* #return DateTime
*/
public function getTimeEnd()
{
return $this->timeEnd;
}
/**
* #return \PMTool\ApiBundle\Entity\Task
*/
public function getTask()
{
return $this->task;
}
/**
* #param \PMTool\ApiBundle\Entity\Task $task
* #return $this
*/
public function setTask($task)
{
$this->task = $task;
return $this;
}
/**
* #return \PMTool\ApiBundle\Entity\ProjectMember
*/
public function getProjectMember()
{
return $this->projectMember;
}
/**
* #param \PMTool\ApiBundle\Entity\ProjectMember $projectMember
* #return $this
*/
public function setProjectMember($projectMember)
{
$this->projectMember = $projectMember;
return $this;
}
}
You can use a transformer to achieve this. (See Symfony Transformers)
Here is an Example of my FormType:
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
...
$transformer = new DateTimeToTimestampTransformer();
$builder->add($builder->create('validFrom', 'text')
->addModelTransformer($transformer)
)
Be sure to use "'text'" as an input type, otherwise it didn't work for me.
the input option is just for the model side of your underlying data object. In your case it should be datetime.
Your problem is, that you want to transform the timestamp into view data that the symfony form datetime form type does recognise. And I dont know how to do that, unfortunately.
http://symfony.com/doc/current/reference/forms/types/datetime.html#input