must return a string value in zend2. How? - doctrine-orm

I have a problem with a zend2 form. I made an entity which gets some data from the database and joins some tables...
here is the entity:
class Campaigns
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
*
* #ORM\Column(name="campaign_name", type="string")
*
*/
protected $campaigns;
/**
* #var mixed
*
* #ORM\ManyToMany(targetEntity="Application\Entity\Countries", cascade={"persist"}, orphanRemoval=false)
* #ORM\JoinTable(name="campaigns_countries",
* joinColumns={#ORM\JoinColumn(name="campaign_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="country_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
protected $countries;
Below this code are the getters and setters, a construct function, an add and an remove function.
Here they are:
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
return $this;
}
public function getCampaigns()
{
return $this->campaigns;
}
public function setCampaigns($campaigns)
{
$this->campaigns = $campaigns;
return $this;
}
public function addCampaigns($campaigns = null)
{
foreach ($campaigns as $c) {
if (!$this->campaigns->contains($c)) {
$this->campaigns->add($c);
}
}
}
public function removeCampaigns($campaigns)
{
foreach ($campaigns as $c) {
if ($this->campaigns->contains($c)) {
$this->campaigns->removeElement($c);
}
}
}
public function getCountries()
{
return $this->countries;
}
public function setCountries($countries)
{
$this->countries = $countries;
return $this;
}
public function addCountries($countries = null)
{
foreach ($countries as $c) {
if (!$this->countries->contains($c)) {
$this->countries->add($c);
}
}
}
public function removeCountries($countries)
{
foreach ($countries as $c) {
if ($this->countries->contains($c)) {
$this->countries->removeElement($c);
}
}
} //construct for countries
public function __construct()
{
$this->setCountries(new ArrayCollection());
}
My problem is with the protected $countries. If i add in the form the property value, it gives me the "countries" property not found in entity.
If I do not add it, and instead use __toString() function, it gives me an error saying that it could not convert countries to string...in the __toString() function I added the following code:
public function __toString()
{
return $this->countries;
}
Thank you for all your help!
AE

You say you want a string containing all related countries. The following code demonstrates how you could achieve this:
$campaignCountryNames = array();
$campaignCountries = $campaign->getCountries();
foreach ($campaignCountries as $country) {
// I assume your Country entity has a name property
$campaignCountryNames[] = $country->getName();
}
echo implode(', ', $campaignCountryNames);

Related

Doctrine 2 avec Symfony 4.2.5 et FOSRestBundle - OneToMany association - Redondant registering

Here is the problem:
Two entities Books and Auteurs. A book has only one auteur, an auteur can have multiple books.
When the base is populated if I create a book with an existing auteur in the Auteurs table, this one creates (wrongly) a duplicate in the table.
The presence of the cascade = "persist" annotation is at the origin of this duplicate. If I delete this annotation I get the error:
{"error": {"code": 500, "message": "Internal Server Error", "exception": [{"message": "A new entity was found through the relationship 'App \ Entity \ Books # auteur' .....
How to deal with this question?
My code:
Controller:
<?php
namespace App\Controller;
use App\Entity\Books;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
class EcritureController extends FOSRestController
{
/**
* #Rest\Post(
* path = "/creer-book")
* #Rest\View(StatusCode = 201)
* #ParamConverter("book", converter="fos_rest.request_body")
*/
public function creerBook(Books $book)
{
$em->persist($book);
$em->flush();
return $book;
}
}
Entity Books:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\BooksRepository")
*/
class Books
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $titre;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Books", inversedBy="Books", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
*/
private $auteur;
public function getId(): ?int
{
return $this->id;
}
public function getTitre(): ?string
{
return $this->Titre;
}
public function setTitre(string $titre): self
{
$this->titre = $titre;
return $this;
}
public function getAuteur(): ?Auteurs
{
return $this->auteur;
}
public function setAuteur(?Auteurs $auteur): self
{
$this->auteur = $auteur;
return $this;
}
}
Entity Auteurs:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\AuteursRepository")
*/
class Auteurs
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=10)
*/
private $nom;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Books", mappedBy="auteur")
*/
private $books;
public function __construct()
{
$this->books = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
/**
* #return Collection|Books[]
*/
public function getBooks(): Collection
{
return $this->books;
}
public function addBook(Books $book): self
{
if (!$this->books->contains($book)) {
$this->books[] = $book;
$book->setBook($this);
}
return $this;
}
public function removeBook(Books $book): self
{
if ($this->books->contains($book)) {
$this->sujets->removeElement($book);
// set the owning side to null (unless already changed)
if ($book->getAuteur() === $this) {
$book->setAuteur(null);
}
}
return $this;
}
}
The error was to "persist" the "Many" side. It's necessary persist the "One" side, as follows:
$auteurId = $book->getAuteur()->getId();
$auteur= $em->getRepository('App:Auteurs')->find($auteurId);
$response = new Response();
if ($auteur) {
$auteur->addBook($book);
$em->persist($auteur);
$em->flush();
$response->setContent('Chain of your choice', Response::HTTP_OK);
} else {
$response->setContent('Auteur selected doesn\'t exist', Response::HTTP_NOT_ACCEPTABLE);
}
return $response;

Foreign key stays empty after persisting entity with OneToMany association

Given are the following two entity classes
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table()
*/
class Tree
{
/**
* #ORM\Id()
* #ORM\Column(type="guid")
* #ORM\GeneratedValue(strategy="UUID")
* #var string
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Apple", mappedBy="tree", cascade={"persist"})
* #var Collection
*/
private $apples;
public function __construct()
{
$this->setApples(new ArrayCollection());
}
public function toArray(): array
{
return [
'id' => $this->getId(),
];
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getApples(): Collection
{
return $this->apples;
}
public function setApples(Collection $apples): void
{
$this->apples = $apples;
}
}
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table()
*/
class Apple
{
/**
* #ORM\Id()
* #ORM\Column(type="guid")
* #ORM\GeneratedValue(strategy="UUID")
* #var string
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Tree", inversedBy="apples")
* #var Tree
*/
private $tree;
public function toArray(): array
{
return [
'id' => $this->getId(),
];
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getTree(): Tree
{
return $this->tree;
}
public function setTree(Tree $tree): void
{
$this->tree = $tree;
}
}
The database schema looks good except for apple.tree_id being nullable. Is that already an issue in this case?
I'm persisting entries like the following:
<?php
declare(strict_types = 1);
namespace App\Service;
use App\Entity\Apple;
use App\Entity\Tree;
use Doctrine\ORM\EntityManager;
class Gardener
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function plantTree(): array
{
$entityManager = $this->entityManager;
$tree = new Tree();
$blueApple = new Apple();
$redApple = new Apple();
$tree->getApples()->add($blueApple);
$tree->getApples()->add($redApple);
$entityManager->persist($tree);
$entityManager->flush();
return (array) $tree;
}
}
When executing the persist and flush there are no errors or warnings. A tree an two apple entries are beingt store, the apple.tree_id is however always null.
It seems like I have a misconfiguration on the entity classes, but am not sure what it is. I also tried adding a JoinColumn annotation #ORM\JoinColumn(name="tree_id", referencedColumnName="id"), but it did not make any difference.
What changes do I need to make, to have appe.tree_id being set properly?
Your missing the adder & remover functions on the *ToMany side.
If your using Symfony >4 then replace setApples function with:
public function addApple(Apple $apple): Tree
{
$this->apples->add($apple);
return $this;
}
public function removeApple(Apple $apple): Tree
{
$this->apples->removeElement($apple);
return $this;
}
If you're using Zend Framework 3, then replace setApples function with:
public function addApples(array $apples): Tree
{
foreach ($apples as $apple) {
if (! $this->apples->contains($apple) {
$this->apples->add($apple)
$apple->setTree($this);
}
}
return $this;
}
public function removeApples(array $apples): Tree
{
foreach ($apples as $apple) {
if($this->apples->contains($apple) {
$this->apples->remove($apple);
}
}
return $this;
}
Have a read of the Working with Association docs, which show examples and explain how to update back 'n' forth.

Doctrine2 - How to remove ManyToMany associations on add of new ones

I've took a quick look but can't find the answer.
Take the following entities, users who can have many roles:
/**
* #Entity
**/
class User
{
/**
* #ManyToMany(targetEntity="Role", inversedBy="users")
* #JoinTable(name="user_to_roles")
**/
protected $roles;
public function __construct()
{
$this->roles = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addRole(Role $role)
{
$role->addUser($this);
$this->roles[] = $role;
}
public function getRoles()
{
return $this->roles;
}
}
and the roles:
/**
* #Entity
**/
class Role
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
**/
protected $id;
/**
* #ManyToMany(targetEntity="User", mappedBy="roles")
**/
protected $users;
public function __construct()
{
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addUser(User $user)
{
$this->users[] = $user;
}
public function getUsers()
{
return $this->users;
}
}
When I want to update a user I will get the reference, and update like so:
$user = $this>entityManager->getReference('App\Entity\User', $id);
$user->addRole($role);
$this->entityManager->persist($user);
$this->entityManager->flush();
However, this will continuously add new roles to my relational table, whereas I just want to update the current row, or delete it and create a new one (whichever is easier). How can I achieve this?
Try to add this function to your entity:
function setRoles($roles) {
$this->roles = new ArrayCollection($roles);
}
And when you update try this:
$user = $this>entityManager->getReference('App\Entity\User', $id);
$roles = array();
// add your roles to the array roles
$user->setRoles($roles);
$this->entityManager->persist($user);
$this->entityManager->flush();

Constraints like #Assert\NotBlank() annotation for entities does not work in unit test which gives semantical or auto loaded error

When I run the Unit test it gives the following error for the constraints
[Semantical Error] The annotation "#Symfony\Component\Validator\Constraints\NotBlank" in property AppBundle\Entity\User::$username does not exist, or could not be auto-loaded.
Here is my entity
User.class
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* Class User
* #package AppBundle\Entity
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="user")
* #ORM\HasLifecycleCallbacks()
*
*/
class User implements AdvancedUserInterface, \Serializable
{
/** #var double
* #ORM\Column(type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=60, unique=true)
* #Assert\NotBlank()
* #Assert\Email()
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;
/**
* #Assert\NotBlank()
* #Assert\Length(max=4096)
*/
private $plainPassword;
/**
* #var string
* #ORM\Column(name="fullname", type="string", length=100, nullable=false)
* #Assert\NotBlank()
*/
protected $fullname;
/**
* #var \DateTime
* #ORM\Column(name="createdat", type="datetime", nullable=true)
*/
protected $createdat;
/**
* #var \DateTime
* #ORM\Column(name="modifiedat", type="datetime", nullable=true)
*/
protected $modifiedat;
/**
* #ORM\Column(type="boolean", options={"default" = 1}, nullable=false)
*/
private $isactive = true;
public function __construct()
{
$this->updatedTimestamps();
}
/**
* Now we tell doctrine that before we persist or update we call the updatedTimestamps() function.
*
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updatedTimestamps()
{
$this->setModifiedat(new \DateTime(date('Y-m-d H:i:s')));
if($this->getCreatedat() == null)
{
$this->setCreatedat(new \DateTime(date('Y-m-d H:i:s')));
}
}
public function getUsername()
{
return $this->username;
}
public function getSalt()
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return '';
}
public function getPassword()
{
return $this->password;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function eraseCredentials()
{
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->isactive;
}
/** #see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
$this->isactive
));
}
/** #see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
$this->isactive
) = unserialize($serialized);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
*
* #return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set password
*
* #param string $password
*
* #return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Set isactive
*
* #param boolean $isactive
*
* #return User
*/
public function setIsactive($isactive)
{
$this->isactive = $isactive;
return $this;
}
/**
* Get isactive
*
* #return boolean
*/
public function getIsactive()
{
return $this->isactive;
}
/**
* #return mixed
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* #param mixed $plainPassword
*/
public function setPlainPassword($plainPassword)
{
$this->plainPassword = $plainPassword;
}
/**
* Set fullname
*
* #param string $fullname
*
* #return User
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set createdat
*
* #param \DateTime $createdat
*
* #return User
*/
public function setCreatedat($createdat)
{
$this->createdat = $createdat;
return $this;
}
/**
* Get createdat
*
* #return \DateTime
*/
public function getCreatedat()
{
return $this->createdat;
}
/**
* Set modifiedat
*
* #param \DateTime $modifiedat
*
* #return User
*/
public function setModifiedat($modifiedat)
{
$this->modifiedat = $modifiedat;
return $this;
}
/**
* Get modifiedat
*
* #return \DateTime
*/
public function getModifiedat()
{
return $this->modifiedat;
}
/**
* The __toString method allows a class to decide how it will react when it is converted to a string.
*
* #return string
* #link http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring
*/
function __toString()
{
return "id: ". $this->id ." email: ". $this->username . " fullname: ". $this->fullname . " isactive: ". $this->isactive .
" createdat: ". $this->createdat->format('Y-m-d H:i:s') ." updatedat: ". $this->modifiedat->format('Y-m-d H:i:s');
}
}
This is my Unit Test classes:
TestBase.class
namespace tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\DependencyInjection\Container;
use Doctrine\Common\Annotations\AnnotationRegistry;
use AppKernel;
AnnotationRegistry::registerFile("../../../vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
require_once __DIR__ . "/../../../vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php";
class TestBase extends \PHPUnit_Framework_TestCase
{
/**
* #var Application
*/
protected $application;
/**
* #var \Doctrine\ORM\EntityManager
*/
protected $entityManager;
/**
* #var \AppKernel
*/
protected $kernel;
/**
* #var Container
*/
protected $container;
protected function setUp()
{
$this->kernel = new AppKernel("test", true);
$this->kernel->boot();
$this->application = new Application($this->kernel);
$this->application->setAutoExit(false);
// Store the container and the entity manager in test case properties
$this->container = $this->kernel->getContainer();
$this->entityManager = $this->container->get("doctrine")->getManager();
if(is_null($this->entityManager)){
print("upssss entitiy manager is null :(");
}
parent::setUp();
}
public function tearDown()
{
// Shutdown the kernel.
$this->kernel->shutdown();
parent::tearDown();
}
}
And here I test my User class just printing the database..
UserTest.class
namespace tests\AppBundle\Controller;
require_once ("TestBase.php");
class UserTest extends TestBase
{
protected function setUp()
{
parent::setUp();
}
public function tearDown()
{
parent::tearDown();
}
//generic method to list the users
public function listUsers($users ){
echo EOL, EOL;
foreach($users as $user){
echo $user, EOL;
}
echo EOL, EOL;
}
public function testListUsers(){
$users = $this->entityManager->getRepository('AppBundle:User')->findAll();
$this->assertGreaterThan(1, count($users));
$this->listUsers($users);
}
}
By the way it works when I don't use #Assert\NotBlank()
So from code-wise there is no problem at all... I guess it is just about autoloading when unit testing..
I really got stuck for 2 weeks with that..
Ok I found the answer..
When I changed test to dev in AppKernel it worked
old one was this:
$this->kernel = new AppKernel("test", true);
solution
$this->kernel = new AppKernel("dev", true);
I didn't change my AppKernel.php though
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
define('EOL',(PHP_SAPI == 'cli') ? PHP_EOL : '<br />');
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
new Liuggio\ExcelBundle\LiuggioExcelBundle(),
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(),
];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
}
return $bundles;
}
public function getRootDir()
{
return __DIR__;
}
public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
}
public function getLogDir()
{
return dirname(__DIR__).'/var/logs';
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
}

Zend Framework: How should I unit test my Mapper in Zend_Db?

How would I test my mappers in Zend_Db?
Each of my model will have 3 classes:
The Model
The Mapper
The DbTable
Here is my Unit Test:
<?php
// Call Model_BugTest::main() if this source file is executed directly.
if (!defined("PHPUnit_MAIN_METHOD")) {
define("PHPUnit_MAIN_METHOD", "Model_ArtistTest::main");
}
require_once dirname(__FILE__) . '/../../TestHelper.php';
/** Model_Artist */
require_once 'Artist.php';
/**
* Test class for Model_Artist.
*
* #group Models
*/
class Model_ArtistTest extends PHPUnit_Framework_TestCase
{
/**
* Runs the test methods of this class.
*
* #return void
*/
public static function main()
{
$suite = new PHPUnit_Framework_TestSuite("Model_ArtistTest");
$result = PHPUnit_TextUI_TestRunner::run($suite);
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* #return void
*/
public function setUp()
{
$this->model = new Ly_Model_Artist();
}
/**
* Tears down the fixture, for example, close a network connection.
* This method is called after a test is executed.
*
* #return void
*/
public function tearDown()
{
}
public function testCanDoTest()
{
$this->assertTrue(true);
}
public function testCanFindArtist()
{
$artist = "Rage Against the Machine";
$result = $this->model->findbyalpha($artist);
var_dump($result);
}
}
I am using Matthew's TestHelper: http://github.com/weierophinney/bugapp/blob/master/tests/TestHelper.php
The error I get is this:
c:\xampp\htdocs\ly\tests>phpunit --configuration phpunit.xml
PHPUnit 3.4.10 by Sebastian Bergmann.
.
Fatal error: Class 'Ly_Model_ArtistMapper' not found in C:\xampp\htdocs\ly\appli
cation\models\Artist.php on line 72
Seems like the Mapper is not being read. Can anyone show me how to do this kind of testing? I am new to UnitTesting and I am just starting to learn it.
This is my Artist Model
<?php
/**
* Artist Model
*/
class Ly_Model_Artist
{
protected $_id; //a field
protected $_name; //a field
protected $_mapper;
public function __construct(array $options = null)
{
if (is_array($options)) {
$this->setOptions($options);
}
}
public function __set($name, $value)
{
$pieces = explode('_', $name);
foreach($pieces AS $key => $row) {
$pieces[$key] = ucfirst($row);
}
$name = implode('',$pieces);
$method = 'get' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid group property');
}
$this->$method($value);
}
public function __get($name)
{
$pieces = explode('_', $name);
foreach($pieces AS $key => $row) {
$pieces[$key] = ucfirst($row);
}
$name = implode('',$pieces);
$method = 'get' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid group property');
}
return $this->$method();
}
public function setOptions(array $options)
{
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
public function setMapper($mapper)
{
$this->_mapper = $mapper;
return $this;
}
public function getMapper()
{
if (null === $this->_mapper) {
$this->setMapper(new Ly_Model_ArtistMapper());
}
return $this->_mapper;
}
public function setId($id)
{
$this->_id = (int) $id;
return $this;
}
public function getId()
{
return $this->_id;
}
public function setName($text)
{
$this->_name = (string) $text;
return $this;
}
public function getName()
{
return $this->_name;
}
public function find($id)
{
$this->getMapper()->find($id, $this);
return $this;
}
public function findbyalpha($keyword)
{
return $this->getMapper()->findbyalpha($keyword);
}
}
This is the Artist Mapper:
<?php
/**
* Artist Model Mapper
*/
class Ly_Model_ArtistMapper
{
protected $_dbTable;
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Ly_Model_DbTable_Artist');
}
return $this->_dbTable->getAdapter();
}
public function find($id, Ly_Model_Artist $artist)
{
if(!isset($id) OR empty($id)) {
throw new Exception ('Could not find id.');
}
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$artist->setId($row->id)
->setName($row->name);
}
public function findbyalpha($keyword)
{
if(!isset($keyword) OR empty($keyword)) {
throw new Exception ('Could not find keyword.');
}
$keyword = $this->getDbTable()->quote($keyword.'%');
//$sql = $this->getDbTable()->select()->where('twitter_id = ?',$twitter_id)->order('weight');
$sql = "SELECT
DISTINCT
a.name
FROM artist a
WHERE a.name LIKE ".$keyword."
ORDER BY a.name ASC
";
//Zend_Debug::dump($sql);
$result = $this->getDbTable()->fetchAll($sql);
return $result;
}
}
And the Db_Table just looks like this:
<?php
class Ly_Model_DbTable_Artist extends Zend_Db_Table_Abstract
{
protected $_name = 'artist';
}
Change the mapper to use the Inversion of Control pattern (insert the DB Table Object into the constructor (at least optionally) that way you can disconnect it and pass in a mock/stub object.
You should test your models (which call your mapper). That way, you will know if something is wrong with your mappers.
Have you tried in your Artists model setting the mapper method like
public function setMapper(Ly_Model_ArtistMapper $mapper)
{
...
}
Unit tests are meant to test a small amount of work, i.e. a method. Everything that the method depends on should be mocked/stubbed (success/failure) out as that will be tested else where in another unit test.